diff --git a/css/piskel-style-packaged-2014-07-14-04-44.css b/css/piskel-style-packaged-2014-07-14-04-44.css deleted file mode 100644 index cbe61373..00000000 --- a/css/piskel-style-packaged-2014-07-14-04-44.css +++ /dev/null @@ -1,2648 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: radial-gradient(circle, #000, #373737); - /* 16/06/2013 : -webkit still needed for - safari, safari mobile and android browser and chrome for android - cf http://caniuse.com/css-gradients */ - background: -webkit-radial-gradient(circle, #000, #373737); -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} - - - -/** - * User messages - */ -.user-message { - position: absolute; - right: 0; - bottom: 0; - background-color: #F9EDBE; - padding: 10px 47px; - border-top-left-radius: 7px; - color: #222; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - font-weight: bold; - font-size: 13px; - z-index: 30000; - max-width: 300px; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - color: gray; - font-weight: bold; - cursor: pointer; - font-size: 18px; -} - -.user-message .close:hover { - color: black; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} -@font-face { - font-family: 'piskel'; - src:url('fonts/piskel.eot?-3olv93'); - src:url('fonts/piskel.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/piskel.woff?-3olv93') format('woff'), - url('fonts/piskel.ttf?-3olv93') format('truetype'), - url('fonts/piskel.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - - -.row { - display: block; -} - -.textfield { - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; - - box-sizing:border-box; - -moz-box-sizing:border-box; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - height: 24px; - box-sizing: border-box; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0px -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0px 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0px 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - - - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.save-field { - width: 100%; -} - -.save-status { - margin-bottom: 10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} - -.gif-export-progress-status { - margin-left: 5px; -} - -.gif-export-progress-bar { - margin-top:5px; - height:3px; - width: 0; - background:gold; -} - -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float: left; -} - -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-size: 30px 30px; - background-position: 8px 8px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.action-icon.edit-icon { - background-image: url('../img/tools/pen.png'); -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} - -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border : 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field, -.resize-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -.import-size-field:nth-of-type(2), -.resize-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} -.palette-manager-wrapper { - height: 100%; - position: relative; -} - -.palette-manager-body { - position: absolute; - top: 45px; - bottom: 0; - right: 0; - left: 0; -} - -.palette-manager-head { - position: absolute; - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} - -.palette-manager-drawer { - width: 200px; - position: absolute; - top: 0; - bottom: 0; -} - -.palette-manager-list { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; -} - -.palette-manager-actions { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - text-align: center; -} - -.palette-manager-actions-button { - width: 80px; - margin: 5px; -} - -.palette-manager-palette-button, -.palette-manager-actions-button { - line-height: 20px; -} - -.palette-manager-list li { - height: 48px; - line-height: 48px; - padding-left:10px; - - font-size: 1.4em; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-bottom: 1px solid #666; - cursor:pointer; -} - -.palette-manager-list li:hover { - background : #222; -} - -.palette-manager-list li.selected { - color : gold; - font-weight: bold; -} - -.palette-manager-list li:nth-child(1) { - border-top: 1px solid #666; -} - -.palette-manager-details { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 200px; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-left:1px solid #666; -} - -.palette-manager-details-head { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-details-head-name { - padding: 0 10px 0 20px; - font-size: 1.5em; - font-weight: bold; -} - -.palette-manager-details-head .edit-icon { - width: 24px; - display: inline-block; - background-size: 16px; -} - -.palette-manager-details-head-actions { - float: right; - line-height: 40px; - padding-right: 10px; -} - -.palette-manager-details-body { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - - - -.palette-manager-color-card { - width: 120px; - height: 180px; - display: inline-block; - position: relative; - margin: 20px 0 20px 20px; - box-shadow: 0 0 0px 0px gold; - transition: box-shadow 0.3s; -} - -.palette-manager-color-card:hover { - box-shadow: 0 0 4px 1px gold; -} - -.palette-manager-delete-card { - position: absolute; - top: 0; - right: 0; - width: 20px; - - text-align: center; - font-size: 1.6em; - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 2px rgb(0,0,0); - cursor: pointer; - - opacity : 0.2; - transition : opacity 0.3s, color 0.1s; -} - -.palette-manager-color-card:hover .palette-manager-delete-card { - opacity : 0.6; -} - -.palette-manager-color-card .palette-manager-delete-card:hover { - opacity : 1; - color: rgb(240,80,80); -} - -.palette-manager-new-color .palette-manager-color-square { - border: 3px dotted #888; - border-bottom-width: 0; - box-sizing: border-box; - -moz-box-sizing: border-box; - border-radius: 3px 3px 0 0; - cursor: pointer; - text-align: center; - font-size: 24px; - color: #888; - line-height: 120px; -} - -.palette-manager-color-square { - width: 120px; - height: 120px; - cursor: pointer; - /*background-image:url(../img/tools/eyedropper.png);*/ -} - -.palette-manager-color-details { - color : #666; - background: #eee; - height: 60px; - padding-left: 5px; -} - -.palette-manager-color-details li{ - line-height: 20px; - font-weight: bold; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -.toolbox-button-container { - overflow : hidden; -} - -.toolbox-button { - margin: 0; - width: 25%; - float : left; -} - -/* @override */ -.button.toolbox-button { - border-left-width: 0; -} - -.toolbox-button:last-child { - border-right-width: 0; -} - -/** - * Layers container - */ -.layers-list-container { -} - -.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 2em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item .edit-icon { - float: right; - width: 30px; - background-size: 12px; - opacity: 0; - transition : opacity 0.2s; -} - -.layer-item:hover .edit-icon { - opacity : 0.6; -} - -.layer-item:hover .edit-icon:hover { - opacity : 1; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-arrow { - font-family : 'Lucida Grande', Calibri; - padding : 2px 6px 0 6px; -} -.palettes-list-select { - float:right; - max-width:90px; - margin-top: 3px; -} - -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} - -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} - -.palettes-list-color { - cursor : pointer; - float: left; - margin : 0 0 5px 5px; - width : 32px; - height : 32px; - position: relative; -} - -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} - -.palettes-list-color div{ - width : 32px; - height : 32px; -} - -.palettes-list-has-scrollbar .palettes-list-color, -.palettes-list-has-scrollbar .palettes-list-color div{ - width: 29px -} - -.palettes-list-primary-color:before, -.palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - - width: 0px; - height: 0px; -} - -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} - - -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -/** - * Animated preview styles. - */ - -.preview-container { - border : 0px Solid black; - border-radius:5px 0px 0px 5px; - box-shadow : 0px 0px 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0px Solid transparent; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -#animated-preview-canvas-container { - height :200px; - width : 200px; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 1030; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-02-19-01-09.css b/css/piskel-style-packaged-2015-02-19-01-09.css deleted file mode 100644 index dc800a80..00000000 --- a/css/piskel-style-packaged-2015-02-19-01-09.css +++ /dev/null @@ -1,2947 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: #1D1D1D; -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -.no-overflow { - overflow : hidden; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.uppercase { - text-transform: uppercase; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float : left; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} -@font-face { - font-family: 'piskel'; - src:url('fonts/icomoon.eot?-3olv93'); - src:url('fonts/icomoon.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/icomoon.woff?-3olv93') format('woff'), - url('fonts/icomoon.ttf?-3olv93') format('truetype'), - url('fonts/icomoon.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - -.piskel-icon-download:before { - content: "\e600"; -} - -.piskel-icon-rotateleft:before { - content: "\e603"; -} - -.piskel-icon-rotateright:before { - content: "\e604"; -} - -.piskel-icon-fliph:before { - content: "\e605"; -} - -.piskel-icon-flipv:before { - content: "\e606"; -} - -.piskel-icon-trashplain:before { - content: "\e607"; -} - -.piskel-icon-trash:before { - content: "\e608"; -} - -.piskel-icon-merge:before { - content: "\e609"; -} - -.piskel-icon-pencil:before { - content: "\e610"; -} - -.piskel-icon-close:before { - content: "\e611"; -} - -.piskel-icon-minus:before { - content: "\e60a"; -} - -.piskel-icon-plus:before { - content: "\e60b"; -} - -.piskel-icon-arrow-up-fat:before { - content: "\e60c"; -} - -.piskel-icon-arrow-down-fat:before { - content: "\e60d"; -} - -.piskel-icon-arrow-up-thin:before { - content: "\e60e"; -} - -.piskel-icon-arrow-down-thin:before { - content: "\e60f"; -} - -.row { - display: block; -} - -.textfield { - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; - - box-sizing:border-box; - -moz-box-sizing:border-box; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - height: 24px; - box-sizing: border-box; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0px -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0px 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0px 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - - - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} -.resize-section-title { - vertical-align: top; - display: inline-block; - padding-top: 5px; - width: 25%; -} - -.resize-content-checkbox { - margin-left: 0; -} - -.resize-origin-container { - overflow: hidden; - position: relative; - width: 70px; - margin-top: 5px; - display: inline-block; -} - -.resize-origin-option { - float: left; - box-sizing: border-box; - position: relative; - margin: 0 1px 1px 0; - width: 20px; - height: 20px; - background : #888; - font-size: 8px; - text-align: center; - cursor: pointer; -} - -.resize-origin-option.selected { - border : 3px solid gold; -} - -.resize-origin-option:before { - content: ''; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin: -2px; -} - -.resize-origin-option.selected:before { - content: ''; - width: 4px; - height: 4px; - background: gold; -} - -.resize-origin-option[data-neighbor]:before { - width: 0; - height: 0; - border-width: 4px; - border-style: solid; - border-color: transparent; -} - -.resize-origin-option[data-neighbor="bottom"]:before { - border-top-color: gold; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="left"]:before { - border-right-color: gold; - margin-top: -4px; - margin-left: -6px; -} - -.resize-origin-option[data-neighbor="top"]:before { - border-bottom-color: gold; - margin-top: -6px; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="right"]:before { - border-left-color: gold; - margin-top: -4px; -} - -.resize-ratio-checkbox, -.resize-smooth-checkbox { - vertical-align: -2px; - margin-left: 0; -} -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -.color-picker-slider * { - box-sizing: border-box; -} - -.color-picker-slider input[type="range"] { - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - width: 100%; - border: none; - padding: 1px 2px; - border-radius: 3px; - background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); - box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; - outline: none; /* no focus outline */ -} - -/* thumb */ - -.color-picker-slider input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - cursor:pointer; - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ - background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} -.color-picker-slider input[type="range"]::-moz-range-thumb { - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -.color-picker-slider input[type="range"]::-ms-thumb { - width: 7px; - height: 18px; - border-radius: 2px; - border: 0; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -/*CROSS BROWSER RESET*/ - - -.color-picker-slider input[type="range"]::-moz-range-track { - border: inherit; - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-track { - border: inherit; - color: transparent; /* don't drawn vertical reference line */ - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-fill-lower, -.color-picker-slider input[type="range"]::-ms-fill-upper { - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-tooltip { - display: none; -} - -.color-picker-slider, -.color-picker-input { - padding: 0 10px; - height : 25px; - overflow: hidden; -} - -.color-picker-slider span{ - line-height : 25px; - width : 10px; - float:left; -} - -.color-picker-slider input[type="range"]{ - float:left; - height : 10px; - width : 100px; - margin: 7px 1px 7px 8px; -} - -.color-picker-slider input[type="text"]{ - float:left; - width : 47px; - margin-left: 5px; -} - -.color-picker-input { - margin-bottom: 10px; -} - -.color-picker-input .textfield{ - width:100%; -} - -.color-picker-slider input[type="range"][data-dimension="h"] { - background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - height: 100%; - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border : 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field, -.resize-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -.import-size-field:nth-of-type(2), -.resize-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -#dialog-container.create-palette { - width: 500px; - height: 600px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette { - margin-top: -300px; -} - -.create-palette-section { - position: absolute; - left: 10px; - top: 50px; -} - -.create-palette-import-section { - display : inline-block; -} - -.colors-container { - position: absolute; - - left: 10px; - right: 10px; - top: 85px; - - height: 460px; - - border: 1px solid black; - background: #333; -} - -.color-picker-container { - position:absolute; - left : 280px; - top:0; - bottom:0; - right:0; - background: #222; -} - -.create-palette-actions { - position: absolute; - box-sizing: border-box; - - width:100%; - height: 45px; - - left: 0; - right: 0; - bottom: 0; - - padding:10px; - text-align:right; -} - -.color-preview { - width: 170px; - height: 70px; - margin: 11px; -} - -.colors-list { - overflow: auto; - width: 280px; - box-sizing: border-box; - height: 100%; - padding-bottom: 10px; -} - -.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - position:relative; - float : left; - - width : 44px; - height : 44px; - margin : 10px 0 0 10px; - - box-sizing : border-box; - - cursor : pointer; -} - -@-moz-document url-prefix() { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - -@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - - -.create-palette-color { - border:1px solid #2c2c2c; - transition : border-color 0.2s; -} -.create-palette-color:hover { - border:1px solid gold; -} - -.colors-list-drop-proxy { - border:2px dotted #eee; -} - -.create-palette-new-color { - border:2px dotted gold; - - border-radius: 2px; - line-height: 40px; - text-align: center; - font-size: 20px; - color: gold; -} - -.create-palette-color.selected { - border:2px solid gold; -} - -.create-palette-remove-color { - position: absolute; - top: 0; - right: 0; - padding: 2px 4px 0 0; - opacity : 0.2; - - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 1px rgb(0,0,0); - - transition : opacity 0.3s, color 0.1s; -} - -.light-color .create-palette-remove-color { - color: rgb(0,0,0); - text-shadow : 0 0 1px rgb(255,255,255); -} - -.selected .create-palette-remove-color { - top: -1px; - right: -1px; -} - -.create-palette-color:hover .create-palette-remove-color { - opacity: 0.6; -} - -.create-palette-color .create-palette-remove-color:hover { - opacity: 1; - color: rgb(240,80,80); - text-shadow : 0 0 1px rgb(0,0,0); -} - -/*SPECTRUM OVERRIDES*/ - -.create-palette .sp-container{ - background-color: transparent; - border: none; - box-shadow : none; - border-radius:0; - padding:5px; -} -.user-message { - position: absolute; - right: 0; - bottom: 0; - padding: 10px 47px; - max-width: 300px; - - border-top-left-radius: 7px; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - - color: #222; - background-color: #F9EDBE; - - font-weight: bold; - font-size: 13px; - - z-index: 30000; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - - color: gray; - - font-size: 18px; - font-weight: bold; - - cursor: pointer; -} - -.user-message .close:hover { - color: black; -} - -.progress-bar-container { - position: absolute; - left: 0; - bottom: 0; - padding: 10px; - width: 360px; - border-top-right-radius: 2px; - border: gold 2px solid; - border-left: 0; - border-bottom: 0; - background-color: #444; - font-size: 14px; - z-index: 30000; - color: #eee; -} - -.progress-bar-item { - float: left; - height:20px; -} - -.progress-bar-status { - line-height: 20px; - width : 40px; - overflow : hidden; - margin: 0 0 0 10px; -} - -.progress-bar { - border : 1px solid grey; - margin-top: 8px; - height : 4px; - width : 300px; - background : linear-gradient(to left, gold, gold) no-repeat -300px 0; - background-color : black; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -/** - * Layers container - */ -.layers-list-container { -} - -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - -.layers-title { - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 0.5em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-container { - overflow : hidden; -} - -.layers-button { - margin: 0; - width: 16.66667%; - float : left; -} - -/* @override */ -.layers-button-container .layers-button { - border-left-width: 0; -} - -.layers-button:last-child { - border-right-width: 0; -} -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} -.palettes-list-color { - cursor: pointer; - float: left; - margin: 0 0 5px 5px; - width: 32px; - height: 32px; - position: relative; -} -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} -.palettes-list-color div { - width: 32px; - height: 32px; -} -.palettes-list-has-scrollbar .palettes-list-color, .palettes-list-has-scrollbar .palettes-list-color div { - width: 29px -} -.palettes-list-primary-color:before, .palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - width: 0px; - height: 0px; -} -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -.palettes-list-actions { - background-color: #3f3f3f; - border-bottom-color: #222; - height: 24px; - padding: 0; - overflow: hidden; -} - -.palettes-list-button, -.palettes-list-select { - margin: 0; - float: left; -} - -.palettes-list-button { - width: 16.66667%; -} -.palettes-list-select { - width: 66.66667%; - height: 100%; - padding: 0 5px 0 5px; - - border-style: solid; - border-width: 1px 0 1px 0; - - color: #aaa; - font-size : 0.75em; - - /*thanks firefox, you suck*/ - text-align:left; - /*text-shadow:none;*/ - font-weight: normal; - - transition : background-color 0.3s, color 0.3s; - cursor:pointer; -} - -.palettes-list-select:hover { - color: white; - background-color: #484848; -} - -.palettes-list-select:focus { - background-color: #484848; - color: white; - outline: none; -} - -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} -.palettes-list-no-colors { - height: 42px; - width: 100%; - color: grey; - font-size: 0.7em; - font-style: italic; - line-height: 42px; - text-align: center -} - -/** - * Animated preview styles. - */ - -.preview-container { - border : 0 Solid black; - border-radius:5px 0 0 5px; - box-shadow : 0 0 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0 Solid transparent; -} - -.canvas-container .animated-preview-canvas-background { - position : relative; - height: 100%; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -.canvas-container-wrapper { - height :200px; - width : 200px; - overflow:hidden; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} -.transformations-container .tool-icon { - float:left; -} -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 30000; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-03-02-09-38.css b/css/piskel-style-packaged-2015-03-02-09-38.css deleted file mode 100644 index 8017ce2e..00000000 --- a/css/piskel-style-packaged-2015-03-02-09-38.css +++ /dev/null @@ -1,3005 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: #1D1D1D; -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -.no-overflow { - overflow : hidden; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.uppercase { - text-transform: uppercase; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float : left; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} -@font-face { - font-family: 'piskel'; - src:url('fonts/icomoon.eot?-3olv93'); - src:url('fonts/icomoon.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/icomoon.woff?-3olv93') format('woff'), - url('fonts/icomoon.ttf?-3olv93') format('truetype'), - url('fonts/icomoon.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - -.piskel-icon-download:before { - content: "\e600"; -} - -.piskel-icon-rotateleft:before { - content: "\e603"; -} - -.piskel-icon-rotateright:before { - content: "\e604"; -} - -.piskel-icon-fliph:before { - content: "\e605"; -} - -.piskel-icon-flipv:before { - content: "\e606"; -} - -.piskel-icon-trashplain:before { - content: "\e607"; -} - -.piskel-icon-trash:before { - content: "\e608"; -} - -.piskel-icon-merge:before { - content: "\e609"; -} - -.piskel-icon-pencil:before { - content: "\e610"; -} - -.piskel-icon-close:before { - content: "\e611"; -} - -.piskel-icon-minus:before { - content: "\e60a"; -} - -.piskel-icon-plus:before { - content: "\e60b"; -} - -.piskel-icon-arrow-up-fat:before { - content: "\e60c"; -} - -.piskel-icon-arrow-down-fat:before { - content: "\e60d"; -} - -.piskel-icon-arrow-up-thin:before { - content: "\e60e"; -} - -.piskel-icon-arrow-down-thin:before { - content: "\e60f"; -} - -.row { - display: block; -} - -.textfield { - box-sizing:border-box; - - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - box-sizing: border-box; - height: 24px; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0 -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.anonymous .save-public-section, -.anonymous #save-online-button { - display : none; -} - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} -.tiled-preview-checkbox { - vertical-align: -2px; - margin-left: 0; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} -.resize-section-title { - vertical-align: top; - display: inline-block; - padding-top: 5px; - width: 25%; -} - -.resize-content-checkbox { - margin-left: 0; -} - -.resize-ratio-checkbox, -.resize-smooth-checkbox { - vertical-align: -2px; - margin-left: 0; -} - - -/*****************/ -/* ANCHOR WIDGET */ -/*****************/ - -.resize-origin-container { - overflow: hidden; - position: relative; - width: 70px; - margin-top: 5px; - display: inline-block; -} - -.transition .resize-origin-option, -.transition .resize-origin-option:before { - transition: background-color 0.2s, border-color 0.2s; -} - -.resize-origin-option { - float: left; - position: relative; - - box-sizing: border-box; - margin: 0 1px 1px 0; - width: 20px; - height: 20px; - - background : #888; - - font-size: 8px; - text-align: center; - cursor: pointer; -} - -.disabled .resize-origin-option { - cursor: default; - background : #555; - border-color: #555 !important; -} - -.resize-origin-option.selected { - border : 3px solid gold; -} - -.resize-origin-option:before { - content: ''; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin: -2px; -} - -.resize-origin-option.selected:before { - content: ''; - width: 4px; - height: 4px; - background: gold; -} - -.disabled .resize-origin-option.selected:before { - background: #555; -} - -.disabled .resize-origin-option[data-neighbor]:before { - border-color: #555 !important; -} - -.resize-origin-option[data-neighbor]:before { - width: 0; - height: 0; - border-width: 4px; - border-style: solid; - border-color: transparent; -} - -.resize-origin-option[data-neighbor="bottom"]:before { - border-top-color: gold; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="left"]:before { - border-right-color: gold; - margin-top: -4px; - margin-left: -6px; -} - -.resize-origin-option[data-neighbor="top"]:before { - border-bottom-color: gold; - margin-top: -6px; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="right"]:before { - border-left-color: gold; - margin-top: -4px; -} -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -.color-picker-slider * { - box-sizing: border-box; -} - -.color-picker-slider input[type="range"] { - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - width: 100%; - border: none; - padding: 1px 2px; - border-radius: 3px; - background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); - box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; - outline: none; /* no focus outline */ -} - -/* thumb */ - -.color-picker-slider input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - cursor:pointer; - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ - background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} -.color-picker-slider input[type="range"]::-moz-range-thumb { - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -.color-picker-slider input[type="range"]::-ms-thumb { - width: 7px; - height: 18px; - border-radius: 2px; - border: 0; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -/*CROSS BROWSER RESET*/ - - -.color-picker-slider input[type="range"]::-moz-range-track { - border: inherit; - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-track { - border: inherit; - color: transparent; /* don't drawn vertical reference line */ - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-fill-lower, -.color-picker-slider input[type="range"]::-ms-fill-upper { - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-tooltip { - display: none; -} - -.color-picker-slider, -.color-picker-input { - padding: 0 10px; - height : 25px; - overflow: hidden; -} - -.color-picker-slider span{ - line-height : 25px; - width : 10px; - float:left; -} - -.color-picker-slider input[type="range"]{ - float:left; - height : 10px; - width : 100px; - margin: 7px 1px 7px 8px; -} - -.color-picker-slider input[type="text"]{ - float:left; - width : 47px; - margin-left: 5px; -} - -.color-picker-input { - margin-bottom: 10px; -} - -.color-picker-input .textfield{ - width:100%; -} - -.color-picker-slider input[type="range"][data-dimension="h"] { - background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - height: 100%; - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border : 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field, -.resize-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -.import-size-field:nth-of-type(2), -.resize-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -#dialog-container.create-palette { - width: 500px; - height: 600px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette { - margin-top: -300px; -} - -.create-palette-section { - position: absolute; - left: 10px; - top: 50px; -} - -.create-palette-import-section { - display : inline-block; -} - -.colors-container { - position: absolute; - - left: 10px; - right: 10px; - top: 85px; - - height: 460px; - - border: 1px solid black; - background: #333; -} - -.color-picker-container { - position:absolute; - left : 280px; - top:0; - bottom:0; - right:0; - background: #222; -} - -.create-palette-actions { - position: absolute; - box-sizing: border-box; - - width:100%; - height: 45px; - - left: 0; - right: 0; - bottom: 0; - - padding:10px; - text-align:right; -} - -.color-preview { - width: 170px; - height: 70px; - margin: 11px; -} - -.colors-list { - overflow: auto; - width: 280px; - box-sizing: border-box; - height: 100%; - padding-bottom: 10px; -} - -.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - position:relative; - float : left; - - width : 44px; - height : 44px; - margin : 10px 0 0 10px; - - box-sizing : border-box; - - cursor : pointer; -} - -@-moz-document url-prefix() { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - -@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - - -.create-palette-color { - border:1px solid #2c2c2c; - transition : border-color 0.2s; -} -.create-palette-color:hover { - border:1px solid gold; -} - -.colors-list-drop-proxy { - border:2px dotted #eee; -} - -.create-palette-new-color { - border:2px dotted gold; - - border-radius: 2px; - line-height: 40px; - text-align: center; - font-size: 20px; - color: gold; -} - -.create-palette-color.selected { - border:2px solid gold; -} - -.create-palette-remove-color { - position: absolute; - top: 0; - right: 0; - padding: 2px 4px 0 0; - opacity : 0.2; - - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 1px rgb(0,0,0); - - transition : opacity 0.3s, color 0.1s; -} - -.light-color .create-palette-remove-color { - color: rgb(0,0,0); - text-shadow : 0 0 1px rgb(255,255,255); -} - -.selected .create-palette-remove-color { - top: -1px; - right: -1px; -} - -.create-palette-color:hover .create-palette-remove-color { - opacity: 0.6; -} - -.create-palette-color .create-palette-remove-color:hover { - opacity: 1; - color: rgb(240,80,80); - text-shadow : 0 0 1px rgb(0,0,0); -} - -/*SPECTRUM OVERRIDES*/ - -.create-palette .sp-container{ - background-color: transparent; - border: none; - box-shadow : none; - border-radius:0; - padding:5px; -} -.user-message { - position: absolute; - right: 0; - bottom: 0; - padding: 10px 47px; - max-width: 300px; - - border-top-left-radius: 7px; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - - color: #222; - background-color: #F9EDBE; - - font-weight: bold; - font-size: 13px; - - z-index: 30000; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - - color: gray; - - font-size: 18px; - font-weight: bold; - - cursor: pointer; -} - -.user-message .close:hover { - color: black; -} - -.progress-bar-container { - position: absolute; - left: 0; - bottom: 0; - padding: 10px; - width: 360px; - border-top-right-radius: 2px; - border: gold 2px solid; - border-left: 0; - border-bottom: 0; - background-color: #444; - font-size: 14px; - z-index: 30000; - color: #eee; -} - -.progress-bar-item { - float: left; - height:20px; -} - -.progress-bar-status { - line-height: 20px; - width : 40px; - overflow : hidden; - margin: 0 0 0 10px; -} - -.progress-bar { - border : 1px solid grey; - margin-top: 8px; - height : 4px; - width : 300px; - background : linear-gradient(to left, gold, gold) no-repeat -300px 0; - background-color : black; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -/** - * Layers container - */ -.layers-list-container { -} - -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - -.layers-title { - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 0.5em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-container { - overflow : hidden; -} - -.layers-button { - margin: 0; - width: 16.66667%; - float : left; -} - -/* @override */ -.layers-button-container .layers-button { - border-left-width: 0; -} - -.layers-button:last-child { - border-right-width: 0; -} -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} -.palettes-list-color { - cursor: pointer; - float: left; - margin: 0 0 5px 5px; - width: 32px; - height: 32px; - position: relative; -} -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} -.palettes-list-color div { - width: 32px; - height: 32px; -} -.palettes-list-has-scrollbar .palettes-list-color, .palettes-list-has-scrollbar .palettes-list-color div { - width: 29px -} -.palettes-list-primary-color:before, .palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - width: 0px; - height: 0px; -} -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -.palettes-list-actions { - background-color: #3f3f3f; - border-bottom-color: #222; - height: 24px; - padding: 0; - overflow: hidden; -} - -.palettes-list-button, -.palettes-list-select { - margin: 0; - float: left; -} - -.palettes-list-button { - width: 16.66667%; -} -.palettes-list-select { - width: 66.66667%; - height: 100%; - padding: 0 5px 0 5px; - - border-style: solid; - border-width: 1px 0 1px 0; - - color: #aaa; - font-size : 0.75em; - - /*thanks firefox, you suck*/ - text-align:left; - /*text-shadow:none;*/ - font-weight: normal; - - transition : background-color 0.3s, color 0.3s; - cursor:pointer; -} - -.palettes-list-select:hover { - color: white; - background-color: #484848; -} - -.palettes-list-select:focus { - background-color: #484848; - color: white; - outline: none; -} - -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} -.palettes-list-no-colors { - height: 42px; - width: 100%; - color: grey; - font-size: 0.7em; - font-style: italic; - line-height: 42px; - text-align: center -} - -/** - * Animated preview styles. - */ - -.preview-container { - border : 0 Solid black; - border-radius:5px 0 0 5px; - box-shadow : 0 0 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0 Solid transparent; -} - -.canvas-container .animated-preview-canvas-background { - position : relative; - height: 100%; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -.canvas-container-wrapper { - height :200px; - width : 200px; - overflow:hidden; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} - -.open-popup-preview-button { - position : absolute; - z-index: 500; - right : 10px; - top : 10px; - width : 24px; - height: 18px; - - border : 2px solid white; - background : rgba(0,0,0,0.3); - cursor : pointer; - - opacity: 0; - transition: 0.3s opacity, 0.3s border-color; -} - -.minimap-container:hover .open-popup-preview-button { - opacity: 1; -} - -.open-popup-preview-button:hover { - border-color: gold; -} - -.transformations-container .tool-icon { - float:left; -} -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 30000; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-03-02-09-41.css b/css/piskel-style-packaged-2015-03-02-09-41.css deleted file mode 100644 index 8017ce2e..00000000 --- a/css/piskel-style-packaged-2015-03-02-09-41.css +++ /dev/null @@ -1,3005 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: #1D1D1D; -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -.no-overflow { - overflow : hidden; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.uppercase { - text-transform: uppercase; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float : left; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} -@font-face { - font-family: 'piskel'; - src:url('fonts/icomoon.eot?-3olv93'); - src:url('fonts/icomoon.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/icomoon.woff?-3olv93') format('woff'), - url('fonts/icomoon.ttf?-3olv93') format('truetype'), - url('fonts/icomoon.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - -.piskel-icon-download:before { - content: "\e600"; -} - -.piskel-icon-rotateleft:before { - content: "\e603"; -} - -.piskel-icon-rotateright:before { - content: "\e604"; -} - -.piskel-icon-fliph:before { - content: "\e605"; -} - -.piskel-icon-flipv:before { - content: "\e606"; -} - -.piskel-icon-trashplain:before { - content: "\e607"; -} - -.piskel-icon-trash:before { - content: "\e608"; -} - -.piskel-icon-merge:before { - content: "\e609"; -} - -.piskel-icon-pencil:before { - content: "\e610"; -} - -.piskel-icon-close:before { - content: "\e611"; -} - -.piskel-icon-minus:before { - content: "\e60a"; -} - -.piskel-icon-plus:before { - content: "\e60b"; -} - -.piskel-icon-arrow-up-fat:before { - content: "\e60c"; -} - -.piskel-icon-arrow-down-fat:before { - content: "\e60d"; -} - -.piskel-icon-arrow-up-thin:before { - content: "\e60e"; -} - -.piskel-icon-arrow-down-thin:before { - content: "\e60f"; -} - -.row { - display: block; -} - -.textfield { - box-sizing:border-box; - - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - box-sizing: border-box; - height: 24px; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0 -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.anonymous .save-public-section, -.anonymous #save-online-button { - display : none; -} - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} -.tiled-preview-checkbox { - vertical-align: -2px; - margin-left: 0; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} -.resize-section-title { - vertical-align: top; - display: inline-block; - padding-top: 5px; - width: 25%; -} - -.resize-content-checkbox { - margin-left: 0; -} - -.resize-ratio-checkbox, -.resize-smooth-checkbox { - vertical-align: -2px; - margin-left: 0; -} - - -/*****************/ -/* ANCHOR WIDGET */ -/*****************/ - -.resize-origin-container { - overflow: hidden; - position: relative; - width: 70px; - margin-top: 5px; - display: inline-block; -} - -.transition .resize-origin-option, -.transition .resize-origin-option:before { - transition: background-color 0.2s, border-color 0.2s; -} - -.resize-origin-option { - float: left; - position: relative; - - box-sizing: border-box; - margin: 0 1px 1px 0; - width: 20px; - height: 20px; - - background : #888; - - font-size: 8px; - text-align: center; - cursor: pointer; -} - -.disabled .resize-origin-option { - cursor: default; - background : #555; - border-color: #555 !important; -} - -.resize-origin-option.selected { - border : 3px solid gold; -} - -.resize-origin-option:before { - content: ''; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin: -2px; -} - -.resize-origin-option.selected:before { - content: ''; - width: 4px; - height: 4px; - background: gold; -} - -.disabled .resize-origin-option.selected:before { - background: #555; -} - -.disabled .resize-origin-option[data-neighbor]:before { - border-color: #555 !important; -} - -.resize-origin-option[data-neighbor]:before { - width: 0; - height: 0; - border-width: 4px; - border-style: solid; - border-color: transparent; -} - -.resize-origin-option[data-neighbor="bottom"]:before { - border-top-color: gold; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="left"]:before { - border-right-color: gold; - margin-top: -4px; - margin-left: -6px; -} - -.resize-origin-option[data-neighbor="top"]:before { - border-bottom-color: gold; - margin-top: -6px; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="right"]:before { - border-left-color: gold; - margin-top: -4px; -} -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -.color-picker-slider * { - box-sizing: border-box; -} - -.color-picker-slider input[type="range"] { - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - width: 100%; - border: none; - padding: 1px 2px; - border-radius: 3px; - background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); - box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; - outline: none; /* no focus outline */ -} - -/* thumb */ - -.color-picker-slider input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - cursor:pointer; - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ - background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} -.color-picker-slider input[type="range"]::-moz-range-thumb { - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -.color-picker-slider input[type="range"]::-ms-thumb { - width: 7px; - height: 18px; - border-radius: 2px; - border: 0; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -/*CROSS BROWSER RESET*/ - - -.color-picker-slider input[type="range"]::-moz-range-track { - border: inherit; - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-track { - border: inherit; - color: transparent; /* don't drawn vertical reference line */ - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-fill-lower, -.color-picker-slider input[type="range"]::-ms-fill-upper { - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-tooltip { - display: none; -} - -.color-picker-slider, -.color-picker-input { - padding: 0 10px; - height : 25px; - overflow: hidden; -} - -.color-picker-slider span{ - line-height : 25px; - width : 10px; - float:left; -} - -.color-picker-slider input[type="range"]{ - float:left; - height : 10px; - width : 100px; - margin: 7px 1px 7px 8px; -} - -.color-picker-slider input[type="text"]{ - float:left; - width : 47px; - margin-left: 5px; -} - -.color-picker-input { - margin-bottom: 10px; -} - -.color-picker-input .textfield{ - width:100%; -} - -.color-picker-slider input[type="range"][data-dimension="h"] { - background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - height: 100%; - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border : 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field, -.resize-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -.import-size-field:nth-of-type(2), -.resize-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -#dialog-container.create-palette { - width: 500px; - height: 600px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette { - margin-top: -300px; -} - -.create-palette-section { - position: absolute; - left: 10px; - top: 50px; -} - -.create-palette-import-section { - display : inline-block; -} - -.colors-container { - position: absolute; - - left: 10px; - right: 10px; - top: 85px; - - height: 460px; - - border: 1px solid black; - background: #333; -} - -.color-picker-container { - position:absolute; - left : 280px; - top:0; - bottom:0; - right:0; - background: #222; -} - -.create-palette-actions { - position: absolute; - box-sizing: border-box; - - width:100%; - height: 45px; - - left: 0; - right: 0; - bottom: 0; - - padding:10px; - text-align:right; -} - -.color-preview { - width: 170px; - height: 70px; - margin: 11px; -} - -.colors-list { - overflow: auto; - width: 280px; - box-sizing: border-box; - height: 100%; - padding-bottom: 10px; -} - -.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - position:relative; - float : left; - - width : 44px; - height : 44px; - margin : 10px 0 0 10px; - - box-sizing : border-box; - - cursor : pointer; -} - -@-moz-document url-prefix() { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - -@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - - -.create-palette-color { - border:1px solid #2c2c2c; - transition : border-color 0.2s; -} -.create-palette-color:hover { - border:1px solid gold; -} - -.colors-list-drop-proxy { - border:2px dotted #eee; -} - -.create-palette-new-color { - border:2px dotted gold; - - border-radius: 2px; - line-height: 40px; - text-align: center; - font-size: 20px; - color: gold; -} - -.create-palette-color.selected { - border:2px solid gold; -} - -.create-palette-remove-color { - position: absolute; - top: 0; - right: 0; - padding: 2px 4px 0 0; - opacity : 0.2; - - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 1px rgb(0,0,0); - - transition : opacity 0.3s, color 0.1s; -} - -.light-color .create-palette-remove-color { - color: rgb(0,0,0); - text-shadow : 0 0 1px rgb(255,255,255); -} - -.selected .create-palette-remove-color { - top: -1px; - right: -1px; -} - -.create-palette-color:hover .create-palette-remove-color { - opacity: 0.6; -} - -.create-palette-color .create-palette-remove-color:hover { - opacity: 1; - color: rgb(240,80,80); - text-shadow : 0 0 1px rgb(0,0,0); -} - -/*SPECTRUM OVERRIDES*/ - -.create-palette .sp-container{ - background-color: transparent; - border: none; - box-shadow : none; - border-radius:0; - padding:5px; -} -.user-message { - position: absolute; - right: 0; - bottom: 0; - padding: 10px 47px; - max-width: 300px; - - border-top-left-radius: 7px; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - - color: #222; - background-color: #F9EDBE; - - font-weight: bold; - font-size: 13px; - - z-index: 30000; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - - color: gray; - - font-size: 18px; - font-weight: bold; - - cursor: pointer; -} - -.user-message .close:hover { - color: black; -} - -.progress-bar-container { - position: absolute; - left: 0; - bottom: 0; - padding: 10px; - width: 360px; - border-top-right-radius: 2px; - border: gold 2px solid; - border-left: 0; - border-bottom: 0; - background-color: #444; - font-size: 14px; - z-index: 30000; - color: #eee; -} - -.progress-bar-item { - float: left; - height:20px; -} - -.progress-bar-status { - line-height: 20px; - width : 40px; - overflow : hidden; - margin: 0 0 0 10px; -} - -.progress-bar { - border : 1px solid grey; - margin-top: 8px; - height : 4px; - width : 300px; - background : linear-gradient(to left, gold, gold) no-repeat -300px 0; - background-color : black; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -/** - * Layers container - */ -.layers-list-container { -} - -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - -.layers-title { - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 0.5em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-container { - overflow : hidden; -} - -.layers-button { - margin: 0; - width: 16.66667%; - float : left; -} - -/* @override */ -.layers-button-container .layers-button { - border-left-width: 0; -} - -.layers-button:last-child { - border-right-width: 0; -} -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} -.palettes-list-color { - cursor: pointer; - float: left; - margin: 0 0 5px 5px; - width: 32px; - height: 32px; - position: relative; -} -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} -.palettes-list-color div { - width: 32px; - height: 32px; -} -.palettes-list-has-scrollbar .palettes-list-color, .palettes-list-has-scrollbar .palettes-list-color div { - width: 29px -} -.palettes-list-primary-color:before, .palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - width: 0px; - height: 0px; -} -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -.palettes-list-actions { - background-color: #3f3f3f; - border-bottom-color: #222; - height: 24px; - padding: 0; - overflow: hidden; -} - -.palettes-list-button, -.palettes-list-select { - margin: 0; - float: left; -} - -.palettes-list-button { - width: 16.66667%; -} -.palettes-list-select { - width: 66.66667%; - height: 100%; - padding: 0 5px 0 5px; - - border-style: solid; - border-width: 1px 0 1px 0; - - color: #aaa; - font-size : 0.75em; - - /*thanks firefox, you suck*/ - text-align:left; - /*text-shadow:none;*/ - font-weight: normal; - - transition : background-color 0.3s, color 0.3s; - cursor:pointer; -} - -.palettes-list-select:hover { - color: white; - background-color: #484848; -} - -.palettes-list-select:focus { - background-color: #484848; - color: white; - outline: none; -} - -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} -.palettes-list-no-colors { - height: 42px; - width: 100%; - color: grey; - font-size: 0.7em; - font-style: italic; - line-height: 42px; - text-align: center -} - -/** - * Animated preview styles. - */ - -.preview-container { - border : 0 Solid black; - border-radius:5px 0 0 5px; - box-shadow : 0 0 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0 Solid transparent; -} - -.canvas-container .animated-preview-canvas-background { - position : relative; - height: 100%; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -.canvas-container-wrapper { - height :200px; - width : 200px; - overflow:hidden; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} - -.open-popup-preview-button { - position : absolute; - z-index: 500; - right : 10px; - top : 10px; - width : 24px; - height: 18px; - - border : 2px solid white; - background : rgba(0,0,0,0.3); - cursor : pointer; - - opacity: 0; - transition: 0.3s opacity, 0.3s border-color; -} - -.minimap-container:hover .open-popup-preview-button { - opacity: 1; -} - -.open-popup-preview-button:hover { - border-color: gold; -} - -.transformations-container .tool-icon { - float:left; -} -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 30000; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-03-02-09-45.css b/css/piskel-style-packaged-2015-03-02-09-45.css deleted file mode 100644 index 8017ce2e..00000000 --- a/css/piskel-style-packaged-2015-03-02-09-45.css +++ /dev/null @@ -1,3005 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: #1D1D1D; -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -.no-overflow { - overflow : hidden; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.uppercase { - text-transform: uppercase; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float : left; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} -@font-face { - font-family: 'piskel'; - src:url('fonts/icomoon.eot?-3olv93'); - src:url('fonts/icomoon.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/icomoon.woff?-3olv93') format('woff'), - url('fonts/icomoon.ttf?-3olv93') format('truetype'), - url('fonts/icomoon.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - -.piskel-icon-download:before { - content: "\e600"; -} - -.piskel-icon-rotateleft:before { - content: "\e603"; -} - -.piskel-icon-rotateright:before { - content: "\e604"; -} - -.piskel-icon-fliph:before { - content: "\e605"; -} - -.piskel-icon-flipv:before { - content: "\e606"; -} - -.piskel-icon-trashplain:before { - content: "\e607"; -} - -.piskel-icon-trash:before { - content: "\e608"; -} - -.piskel-icon-merge:before { - content: "\e609"; -} - -.piskel-icon-pencil:before { - content: "\e610"; -} - -.piskel-icon-close:before { - content: "\e611"; -} - -.piskel-icon-minus:before { - content: "\e60a"; -} - -.piskel-icon-plus:before { - content: "\e60b"; -} - -.piskel-icon-arrow-up-fat:before { - content: "\e60c"; -} - -.piskel-icon-arrow-down-fat:before { - content: "\e60d"; -} - -.piskel-icon-arrow-up-thin:before { - content: "\e60e"; -} - -.piskel-icon-arrow-down-thin:before { - content: "\e60f"; -} - -.row { - display: block; -} - -.textfield { - box-sizing:border-box; - - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - box-sizing: border-box; - height: 24px; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0 -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.anonymous .save-public-section, -.anonymous #save-online-button { - display : none; -} - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} -.tiled-preview-checkbox { - vertical-align: -2px; - margin-left: 0; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} -.resize-section-title { - vertical-align: top; - display: inline-block; - padding-top: 5px; - width: 25%; -} - -.resize-content-checkbox { - margin-left: 0; -} - -.resize-ratio-checkbox, -.resize-smooth-checkbox { - vertical-align: -2px; - margin-left: 0; -} - - -/*****************/ -/* ANCHOR WIDGET */ -/*****************/ - -.resize-origin-container { - overflow: hidden; - position: relative; - width: 70px; - margin-top: 5px; - display: inline-block; -} - -.transition .resize-origin-option, -.transition .resize-origin-option:before { - transition: background-color 0.2s, border-color 0.2s; -} - -.resize-origin-option { - float: left; - position: relative; - - box-sizing: border-box; - margin: 0 1px 1px 0; - width: 20px; - height: 20px; - - background : #888; - - font-size: 8px; - text-align: center; - cursor: pointer; -} - -.disabled .resize-origin-option { - cursor: default; - background : #555; - border-color: #555 !important; -} - -.resize-origin-option.selected { - border : 3px solid gold; -} - -.resize-origin-option:before { - content: ''; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin: -2px; -} - -.resize-origin-option.selected:before { - content: ''; - width: 4px; - height: 4px; - background: gold; -} - -.disabled .resize-origin-option.selected:before { - background: #555; -} - -.disabled .resize-origin-option[data-neighbor]:before { - border-color: #555 !important; -} - -.resize-origin-option[data-neighbor]:before { - width: 0; - height: 0; - border-width: 4px; - border-style: solid; - border-color: transparent; -} - -.resize-origin-option[data-neighbor="bottom"]:before { - border-top-color: gold; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="left"]:before { - border-right-color: gold; - margin-top: -4px; - margin-left: -6px; -} - -.resize-origin-option[data-neighbor="top"]:before { - border-bottom-color: gold; - margin-top: -6px; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="right"]:before { - border-left-color: gold; - margin-top: -4px; -} -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -.color-picker-slider * { - box-sizing: border-box; -} - -.color-picker-slider input[type="range"] { - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - width: 100%; - border: none; - padding: 1px 2px; - border-radius: 3px; - background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); - box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; - outline: none; /* no focus outline */ -} - -/* thumb */ - -.color-picker-slider input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - cursor:pointer; - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ - background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} -.color-picker-slider input[type="range"]::-moz-range-thumb { - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -.color-picker-slider input[type="range"]::-ms-thumb { - width: 7px; - height: 18px; - border-radius: 2px; - border: 0; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -/*CROSS BROWSER RESET*/ - - -.color-picker-slider input[type="range"]::-moz-range-track { - border: inherit; - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-track { - border: inherit; - color: transparent; /* don't drawn vertical reference line */ - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-fill-lower, -.color-picker-slider input[type="range"]::-ms-fill-upper { - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-tooltip { - display: none; -} - -.color-picker-slider, -.color-picker-input { - padding: 0 10px; - height : 25px; - overflow: hidden; -} - -.color-picker-slider span{ - line-height : 25px; - width : 10px; - float:left; -} - -.color-picker-slider input[type="range"]{ - float:left; - height : 10px; - width : 100px; - margin: 7px 1px 7px 8px; -} - -.color-picker-slider input[type="text"]{ - float:left; - width : 47px; - margin-left: 5px; -} - -.color-picker-input { - margin-bottom: 10px; -} - -.color-picker-input .textfield{ - width:100%; -} - -.color-picker-slider input[type="range"][data-dimension="h"] { - background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - height: 100%; - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border : 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field, -.resize-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -.import-size-field:nth-of-type(2), -.resize-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -#dialog-container.create-palette { - width: 500px; - height: 600px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette { - margin-top: -300px; -} - -.create-palette-section { - position: absolute; - left: 10px; - top: 50px; -} - -.create-palette-import-section { - display : inline-block; -} - -.colors-container { - position: absolute; - - left: 10px; - right: 10px; - top: 85px; - - height: 460px; - - border: 1px solid black; - background: #333; -} - -.color-picker-container { - position:absolute; - left : 280px; - top:0; - bottom:0; - right:0; - background: #222; -} - -.create-palette-actions { - position: absolute; - box-sizing: border-box; - - width:100%; - height: 45px; - - left: 0; - right: 0; - bottom: 0; - - padding:10px; - text-align:right; -} - -.color-preview { - width: 170px; - height: 70px; - margin: 11px; -} - -.colors-list { - overflow: auto; - width: 280px; - box-sizing: border-box; - height: 100%; - padding-bottom: 10px; -} - -.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - position:relative; - float : left; - - width : 44px; - height : 44px; - margin : 10px 0 0 10px; - - box-sizing : border-box; - - cursor : pointer; -} - -@-moz-document url-prefix() { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - -@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - - -.create-palette-color { - border:1px solid #2c2c2c; - transition : border-color 0.2s; -} -.create-palette-color:hover { - border:1px solid gold; -} - -.colors-list-drop-proxy { - border:2px dotted #eee; -} - -.create-palette-new-color { - border:2px dotted gold; - - border-radius: 2px; - line-height: 40px; - text-align: center; - font-size: 20px; - color: gold; -} - -.create-palette-color.selected { - border:2px solid gold; -} - -.create-palette-remove-color { - position: absolute; - top: 0; - right: 0; - padding: 2px 4px 0 0; - opacity : 0.2; - - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 1px rgb(0,0,0); - - transition : opacity 0.3s, color 0.1s; -} - -.light-color .create-palette-remove-color { - color: rgb(0,0,0); - text-shadow : 0 0 1px rgb(255,255,255); -} - -.selected .create-palette-remove-color { - top: -1px; - right: -1px; -} - -.create-palette-color:hover .create-palette-remove-color { - opacity: 0.6; -} - -.create-palette-color .create-palette-remove-color:hover { - opacity: 1; - color: rgb(240,80,80); - text-shadow : 0 0 1px rgb(0,0,0); -} - -/*SPECTRUM OVERRIDES*/ - -.create-palette .sp-container{ - background-color: transparent; - border: none; - box-shadow : none; - border-radius:0; - padding:5px; -} -.user-message { - position: absolute; - right: 0; - bottom: 0; - padding: 10px 47px; - max-width: 300px; - - border-top-left-radius: 7px; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - - color: #222; - background-color: #F9EDBE; - - font-weight: bold; - font-size: 13px; - - z-index: 30000; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - - color: gray; - - font-size: 18px; - font-weight: bold; - - cursor: pointer; -} - -.user-message .close:hover { - color: black; -} - -.progress-bar-container { - position: absolute; - left: 0; - bottom: 0; - padding: 10px; - width: 360px; - border-top-right-radius: 2px; - border: gold 2px solid; - border-left: 0; - border-bottom: 0; - background-color: #444; - font-size: 14px; - z-index: 30000; - color: #eee; -} - -.progress-bar-item { - float: left; - height:20px; -} - -.progress-bar-status { - line-height: 20px; - width : 40px; - overflow : hidden; - margin: 0 0 0 10px; -} - -.progress-bar { - border : 1px solid grey; - margin-top: 8px; - height : 4px; - width : 300px; - background : linear-gradient(to left, gold, gold) no-repeat -300px 0; - background-color : black; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -/** - * Layers container - */ -.layers-list-container { -} - -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - -.layers-title { - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 0.5em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-container { - overflow : hidden; -} - -.layers-button { - margin: 0; - width: 16.66667%; - float : left; -} - -/* @override */ -.layers-button-container .layers-button { - border-left-width: 0; -} - -.layers-button:last-child { - border-right-width: 0; -} -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} -.palettes-list-color { - cursor: pointer; - float: left; - margin: 0 0 5px 5px; - width: 32px; - height: 32px; - position: relative; -} -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} -.palettes-list-color div { - width: 32px; - height: 32px; -} -.palettes-list-has-scrollbar .palettes-list-color, .palettes-list-has-scrollbar .palettes-list-color div { - width: 29px -} -.palettes-list-primary-color:before, .palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - width: 0px; - height: 0px; -} -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -.palettes-list-actions { - background-color: #3f3f3f; - border-bottom-color: #222; - height: 24px; - padding: 0; - overflow: hidden; -} - -.palettes-list-button, -.palettes-list-select { - margin: 0; - float: left; -} - -.palettes-list-button { - width: 16.66667%; -} -.palettes-list-select { - width: 66.66667%; - height: 100%; - padding: 0 5px 0 5px; - - border-style: solid; - border-width: 1px 0 1px 0; - - color: #aaa; - font-size : 0.75em; - - /*thanks firefox, you suck*/ - text-align:left; - /*text-shadow:none;*/ - font-weight: normal; - - transition : background-color 0.3s, color 0.3s; - cursor:pointer; -} - -.palettes-list-select:hover { - color: white; - background-color: #484848; -} - -.palettes-list-select:focus { - background-color: #484848; - color: white; - outline: none; -} - -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} -.palettes-list-no-colors { - height: 42px; - width: 100%; - color: grey; - font-size: 0.7em; - font-style: italic; - line-height: 42px; - text-align: center -} - -/** - * Animated preview styles. - */ - -.preview-container { - border : 0 Solid black; - border-radius:5px 0 0 5px; - box-shadow : 0 0 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0 Solid transparent; -} - -.canvas-container .animated-preview-canvas-background { - position : relative; - height: 100%; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -.canvas-container-wrapper { - height :200px; - width : 200px; - overflow:hidden; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} - -.open-popup-preview-button { - position : absolute; - z-index: 500; - right : 10px; - top : 10px; - width : 24px; - height: 18px; - - border : 2px solid white; - background : rgba(0,0,0,0.3); - cursor : pointer; - - opacity: 0; - transition: 0.3s opacity, 0.3s border-color; -} - -.minimap-container:hover .open-popup-preview-button { - opacity: 1; -} - -.open-popup-preview-button:hover { - border-color: gold; -} - -.transformations-container .tool-icon { - float:left; -} -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 30000; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-04-27-12-01.css b/css/piskel-style-packaged-2015-04-27-12-01.css deleted file mode 100644 index 817f7525..00000000 --- a/css/piskel-style-packaged-2015-04-27-12-01.css +++ /dev/null @@ -1,3017 +0,0 @@ -html, body { - height : 100%; width: 100%; - margin : 0; - overflow: hidden; - cursor : default; - font-family: arial; - font-size: 11px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -ul, li { - margin : 0; - padding : 0; - list-style-type: none; -} - - -/* Force apparition of scrollbars on leopard */ -::-webkit-scrollbar { - -webkit-appearance: none; - width: 6px; -} - -::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: #666; -} - -::-webkit-scrollbar-track { - background-color: rgba(50, 50, 50, 0.4); -} - -a, a:visited { - color:gold; -} -body { - background: #1D1D1D; -} - -/* Browser fixes */ -::-ms-clear { - display: none; -} - -.allow-user-select { - -webkit-touch-callout: initial; - -webkit-user-select: initial; - -khtml-user-select: initial; - -moz-user-select: initial; - -ms-user-select: initial; - user-select: initial; -} - -.no-overflow { - overflow : hidden; -} - -.image-link { - color : gold; -} - -.pull-top, -.pull-right, -.pull-bottom, -.pull-left { - position:absolute; -} - -.pull-top { - top:0; -} - -.pull-right { - right:0; -} - -.pull-bottom { - bottom:0; -} - -.pull-left { - left:0; -} - -.uppercase { - text-transform: uppercase; -} - -/** - * Application layout - */ - -.main-wrapper { - position: absolute; - top: 5px; - right: 0; - bottom: 5px; - left: 0; -} - -.column-wrapper { - text-align: center; - font-size: 0; - position: absolute; - left: 100px; /* Reserve room for tools on the left edge of the screen. */ - top: 0; - right: 50px; /* Reserve room for actions on the right edge of the screen. */ - bottom: 0; -} - -.column { - display: inline-block; -} - -.left-column { - vertical-align: top; - height: 100%; - margin-right: 7px; -} - -.main-column { - height: 100%; - position: relative; -} - -.right-column { - vertical-align: top; - margin-left: 10px; - height: 100%; - position: relative; -} - -.drawing-canvas-container { - font-size: 0; -} - -.sticky-section { - position: fixed; - top: 0; - bottom: 0; - z-index: 1000; -} - -.sticky-section .sticky-section-wrap { - display: table; - height: 100%; -} - -.sticky-section .vertical-centerer { - display: table-cell; - vertical-align: middle; -} - -.left-sticky-section.sticky-section { - left: 0; - max-width: 100px; -} - -.left-sticky-section .tool-icon { - float: left; -} - -.cursor-coordinates { - color:#888; - font-size:12px; - font-weight:bold; - font-family:Courier; -} - -/** - * Canvases layout - */ - -.canvas { - position: relative; - z-index: 1; -} - -.canvas-container { - position: relative; - display: block; -} - -.canvas-container .canvas-background { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.light-picker-background, -.light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; -} - -.medium-picker-background, -.medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; -} - -.lowcont-medium-picker-background, -.lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; -} - -.lowcont-dark-picker-background, -.lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; -} - -.layers-canvas, -.canvas.onion-skin-canvas { - opacity: 0.2; -} - -.canvas.canvas-overlay, -.canvas.layers-canvas, -.canvas.onion-skin-canvas { - position: absolute; - top: 0; - left: 0; -} - -.tools-wrapper, -.options-wrapper, -.palette-wrapper { - float : left; -} - -/** - * Z-indexes should match the drawing area canvas superposition order : - * - 1 : draw layers below current layer - * - 2 : draw current layer - * - 3 : draw layers above current layer - * - 4 : draw the tools overlay - */ -.canvas.layers-below-canvas {z-index: 7;} -.canvas.drawing-canvas {z-index: 8;} -.canvas.canvas-overlay {z-index: 9;} -.canvas.onion-skin-canvas {z-index: 10;} -.canvas.layers-above-canvas {z-index: 11;} -@font-face { - font-family: 'piskel'; - src:url('fonts/icomoon.eot?-3olv93'); - src:url('fonts/icomoon.eot?#iefix-3olv93') format('embedded-opentype'), - url('fonts/icomoon.woff?-3olv93') format('woff'), - url('fonts/icomoon.ttf?-3olv93') format('truetype'), - url('fonts/icomoon.svg?-3olv93#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="piskel-icon-"], [class*=" piskel-icon-"] { - font-family: 'piskel'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.piskel-icon-eye:before { - content: "\e602"; -} - -.piskel-icon-onion:before { - content: "\e601"; -} - -.piskel-icon-download:before { - content: "\e600"; -} - -.piskel-icon-rotateleft:before { - content: "\e603"; -} - -.piskel-icon-rotateright:before { - content: "\e604"; -} - -.piskel-icon-fliph:before { - content: "\e605"; -} - -.piskel-icon-flipv:before { - content: "\e606"; -} - -.piskel-icon-trashplain:before { - content: "\e607"; -} - -.piskel-icon-trash:before { - content: "\e608"; -} - -.piskel-icon-merge:before { - content: "\e609"; -} - -.piskel-icon-pencil:before { - content: "\e610"; -} - -.piskel-icon-close:before { - content: "\e611"; -} - -.piskel-icon-minus:before { - content: "\e60a"; -} - -.piskel-icon-plus:before { - content: "\e60b"; -} - -.piskel-icon-arrow-up-fat:before { - content: "\e60c"; -} - -.piskel-icon-arrow-down-fat:before { - content: "\e60d"; -} - -.piskel-icon-arrow-up-thin:before { - content: "\e60e"; -} - -.piskel-icon-arrow-down-thin:before { - content: "\e60f"; -} - -.row { - display: block; -} - -.textfield { - box-sizing:border-box; - - background : black; - border : 1px solid #888; - border-radius : 2px; - padding : 3px 10px; - color : white; -} - -.textfield[disabled=disabled] { - background : #3a3a3a; -} - -.textfield-small { - width : 50px; -} - -.button { - box-sizing: border-box; - height: 24px; - - background-color: #3f3f3f; - border: 1px solid #333; - border-top-color: #666; - border-bottom-color: #222; - - cursor: pointer; - text-decoration: none; - - color: white; - text-shadow: 0 -1px 0 black; - font-weight: bold; - font-size: 1rem; - text-align: center; - - transition: background-color 0.2s linear; -} - -.button:hover { - text-decoration: none; - background-color: #484848; - color: gold; -} - -.button-primary { - background-color: rgb(255,215,0); /* gold */ - - border-color: rgb(179, 164, 0); - border-top-color: white; - border-bottom-color: rgb(151, 133, 0); - - color: black; - text-shadow: 0 1px 0 #fff; -} - -.button-primary:hover { - background-color: rgb(255,235,20); - color: #333; -} - -.button[disabled], -.button[disabled]:hover { - cursor:default; - background-color: #aaa; - color: #777; - text-shadow: 0 1px 0 #bbb; - border-color: #666; - border-top-color: #999; - border-bottom-color: #555; -} - -.import-size-field, -.resize-size-field, -.export-size-field { - width: 50px; - margin-right: 8px; - text-align: right; -} - -/** Righty sticky drawer expanded state. */ - -.right-sticky-section.sticky-section { - right: 0; - width: 47px; - - -webkit-transition: all 200ms ease-out; - -moz-transition: all 200ms ease-out; - -ms-transition: all 200ms ease-out; - -o-transition: all 200ms ease-out; - transition: all 200ms ease-out; -} - -.right-sticky-section.expanded { - right: 280px; -} - -.right-sticky-section .tool-icon { - float: right; - margin-right: 0; -} - -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - -.tool-icon .label { - position: absolute; - left: 0; - bottom: 4px; - right: 0; - font-size: 11px; - text-transform: uppercase; - color: #fff; - text-align: center; -} - -.drawer-content { - overflow: hidden; - background-color: #444; - height: 550px; - max-height: 100%; - width: 280px; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - box-shadow: 0 0 5px 0 black; -} - -.right-sticky-section.expanded .tool-icon { - padding-right: 1px; -} - -.right-sticky-section .tool-icon.has-expanded-drawer { - position: relative; - background-color: #444; - margin-right: 0; - padding-right: 2px; - border-left : 3px solid gold; -} - -/************************************************************************************************/ -/* Common settings classes */ -/************************************************************************************************/ - -.settings-section { - margin: 10px 20px; - font-size: 12px; - font-weight: bold; - color: #ccc; - text-shadow: 1px 1px #000; -} - -.settings-section .button { - margin: 0; -} - -.settings-title { - color : gold; - margin-top: 20px; - margin-bottom: 10px; - text-transform: uppercase; - border-bottom: 1px #aaa solid; - padding-bottom: 5px; - color: gold; -} - -.settings-description { - margin : 0 0 10px 0; - display : inline-block; -} - -.settings-form-section { - margin-bottom: 10px; -} - -.settings-item { - margin : 10px 0; -} - -[name*=checkbox] { - vertical-align: middle; -} - -/************************************************************************************************/ -/* Application settings */ -/************************************************************************************************/ - -.background-picker-wrapper { - overflow: hidden; - padding: 5px; -} - -.background-picker { - cursor: pointer; - float: left; - height: 35px; - width: 35px; - background-color: transparent; - margin-right: 15px; - padding: 1px; - position: relative; -} - -.background-picker:after { - content: " "; - position: absolute; - top: -2px; - right: -2px; - bottom: -2px; - left: -2px; -} - -.background-picker:hover:after { - border: #eee 1px solid; -} - -.background-picker.selected:after { - border: gold 1px solid; -} - -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.anonymous .save-public-section, -.anonymous #save-online-button { - display : none; -} - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} - -.save-desktop-file-name { - word-wrap: break-word; - font-weight: bold; - color: white; - font-style: normal; -} - -.tiled-preview-checkbox { - vertical-align: -2px; - margin-left: 0; -} -/*******************************/ -/* Gif/Png Export Setting panel*/ -/*******************************/ -.gif-download-button, -.gif-render-button { - margin-top : 10px; - margin-right : 10px; -} - -.gif-export-preview, -.png-export-preview { - position:relative; - margin-top:10px; - max-height:32px; -} - -.gif-export-preview { - max-width:32px; -} - -.png-export-preview img { - max-height:32px; - float: left; -} - -.png-export-preview .light-picker-background { - max-width:240px; -} - -.gif-upload-status { - width: 180px; - margin-left: 5px; - margin-top: 10px; -} - -.gif-upload, -.png-export-preview { - overflow: hidden; -} - -.gif-upload-status, -.gif-export-preview { - float : left; -} - -.preview-upload-ongoing:before{ - content: "Upload ongoing ..."; - position: absolute; - display: block; - height: 100%; - width: 100%; - text-align: center; - padding-top: 45%; - box-sizing:border-box; - -moz-box-sizing:border-box; - background: rgba(0,0,0,0.5); - color: white; -} -/************************************************************************************************/ -/* Import panel */ -/************************************************************************************************/ - -.import-section, -.resize-section { - margin: 10px 0; -} - -.file-input-button { - margin-right: 8px; - border-radius: 2px; -} - -.import-highlight { - font-weight: bold; - color: white; -} -.resize-section-title { - vertical-align: top; - display: inline-block; - padding-top: 5px; - width: 25%; -} - -.resize-content-checkbox { - margin-left: 0; -} - -.resize-ratio-checkbox, -.resize-smooth-checkbox { - vertical-align: -2px; - margin-left: 0; -} - - -/*****************/ -/* ANCHOR WIDGET */ -/*****************/ - -.resize-origin-container { - overflow: hidden; - position: relative; - width: 70px; - margin-top: 5px; - display: inline-block; -} - -.transition .resize-origin-option, -.transition .resize-origin-option:before { - transition: background-color 0.2s, border-color 0.2s; -} - -.resize-origin-option { - float: left; - position: relative; - - box-sizing: border-box; - margin: 0 1px 1px 0; - width: 20px; - height: 20px; - - background : #888; - - font-size: 8px; - text-align: center; - cursor: pointer; -} - -.disabled .resize-origin-option { - cursor: default; - background : #555; - border-color: #555 !important; -} - -.resize-origin-option.selected { - border : 3px solid gold; -} - -.resize-origin-option:before { - content: ''; - position: absolute; - display: block; - top: 50%; - left: 50%; - margin: -2px; -} - -.resize-origin-option.selected:before { - content: ''; - width: 4px; - height: 4px; - background: gold; -} - -.disabled .resize-origin-option.selected:before { - background: #555; -} - -.disabled .resize-origin-option[data-neighbor]:before { - border-color: #555 !important; -} - -.resize-origin-option[data-neighbor]:before { - width: 0; - height: 0; - border-width: 4px; - border-style: solid; - border-color: transparent; -} - -.resize-origin-option[data-neighbor="bottom"]:before { - border-top-color: gold; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="left"]:before { - border-right-color: gold; - margin-top: -4px; - margin-left: -6px; -} - -.resize-origin-option[data-neighbor="top"]:before { - border-bottom-color: gold; - margin-top: -6px; - margin-left: -4px; -} - -.resize-origin-option[data-neighbor="right"]:before { - border-left-color: gold; - margin-top: -4px; -} -.tool-icon { - position : relative; - cursor : pointer; - width: 46px; - height: 46px; - margin: 1px; - background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; -} - -.tool-icon.selected { - cursor: default; - background-color: #444; -} - -.tool-icon.selected:before { - content:""; - position : absolute; - height : 100%; - width : 100%; - border: 3px solid gold; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.tool-icon:hover { - background-color: #444; -} - -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - -/* - * Tool cursors: - */ - -.tool-paint-bucket .drawing-canvas-container:hover, -.tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; -} - -.tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; -} - -.tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; -} - -.tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; -} - -.tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; -} - -.tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; -} - -.tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 15 15, pointer; -} - -.tool-rectangle-select .drawing-canvas-container:hover { - cursor: crosshair; -} - -.tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; -} - -.tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; -} - -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); - position: relative; - top: 50px; - left: 6px; - height: 18px; - width: 18px; - background-size: 18px; - opacity : 0.3; - cursor : pointer; -} - -.swap-colors-icon:hover { - opacity : 1; -} - -.tool-color-picker { - position:relative; -} - -.tool-color-picker:nth-child(1) { - z-index : 100; -} - -.tool-color-picker:nth-child(2) { - z-index : 90; - margin-top: 25px; - margin-left:-20px; -} - -.tool-color-picker input { - width: 16px; - height: 16px; - text-indent: -10000px; - border: 1px solid black; - background: white; - cursor: pointer; - position : relative; - top: 10px; - margin-left: 2px; -} - -.tool-color-picker .secondary-color-picker { - top : 18px; - margin-left: 0; -} - -.palette-wrapper { - margin-top: 10px; - margin-left: 10px; -} - -.palette-color[data-color=TRANSPARENT] { - position: relative; - top: 10px; - left: 10px; - background-color: white; - height : 16px; - width : 16px; - border: 2px solid #000; - background-size: 16px 16px; - background-position: 0 0; - background-image: -webkit-gradient( - linear, - left top, - right bottom, - color-stop(0, #fff), - color-stop(0.45, #fff), - color-stop(0.5, #ff0000), - color-stop(0.55, #fff), - color-stop(1, #fff) - ); - background-image: -moz-linear-gradient( - left top, - #fff 0%, - #fff 45%, - #f00 50%, - #fff 55%, - #fff 100% - ); -} - -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} - -.tools-tooltip-shortcut { - color:gold; -} - -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 50px; - right: 50px; - bottom: 50px; - left: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container h3 { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { - overflow: hidden; - margin: 10px 0; -} - -.cheatsheet-icon.tool-icon { - float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; -} -.color-picker-slider * { - box-sizing: border-box; -} - -.color-picker-slider input[type="range"] { - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - width: 100%; - border: none; - padding: 1px 2px; - border-radius: 3px; - background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); - box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; - outline: none; /* no focus outline */ -} - -/* thumb */ - -.color-picker-slider input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - cursor:pointer; - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ - background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} -.color-picker-slider input[type="range"]::-moz-range-thumb { - width: 7px; - height: 18px; - border: none; - border-radius: 2px; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -.color-picker-slider input[type="range"]::-ms-thumb { - width: 7px; - height: 18px; - border-radius: 2px; - border: 0; - background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ -} - -/*CROSS BROWSER RESET*/ - - -.color-picker-slider input[type="range"]::-moz-range-track { - border: inherit; - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-track { - border: inherit; - color: transparent; /* don't drawn vertical reference line */ - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-fill-lower, -.color-picker-slider input[type="range"]::-ms-fill-upper { - background: transparent; -} - -.color-picker-slider input[type="range"]::-ms-tooltip { - display: none; -} - -.color-picker-slider, -.color-picker-input { - padding: 0 10px; - height : 25px; - overflow: hidden; -} - -.color-picker-slider span{ - line-height : 25px; - width : 10px; - float:left; -} - -.color-picker-slider input[type="range"]{ - float:left; - height : 10px; - width : 100px; - margin: 7px 1px 7px 8px; -} - -.color-picker-slider input[type="text"]{ - float:left; - width : 47px; - margin-left: 5px; -} - -.color-picker-input { - margin-bottom: 10px; -} - -.color-picker-input .textfield{ - width:100%; -} - -.color-picker-slider input[type="range"][data-dimension="h"] { - background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} -#dialog-container-wrapper { - position: absolute; - z-index: 20000; - - top: 0; - right: 0; - bottom: 0; - left: 0; - - padding: 50px 150px; - overflow: hidden; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - background-color: rgba(0,0,0,0.8); - opacity: 0; - pointer-events: none; - - color: white; -} - -#dialog-container-wrapper.animated { - transition: opacity 0.5s; -} - -#dialog-container-wrapper.show { - opacity: 1; - pointer-events: auto; -} - -#dialog-container { - width: 100%; - height: 100%; - - margin-top: -1500px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - border-radius: 3px; - border : 3px solid gold; - background: #444; - overflow: auto; -} - -.animated #dialog-container { - transition:margin-top 0.5s; -} - -.show #dialog-container { - margin-top: 0; -} - -#dialog-container.browse-local { - width: 700px; - height: 500px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -350px; -} - -.show #dialog-container.browse-local { - margin-top: -250px; -} - -#dialog-container.import-image { - width: 500px; - height: 300px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.dialog-wrapper { - height: 100%; - position : relative; -} - -.dialog-head { - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.dialog-close { - position: absolute; - top: 0; - right: 0; - line-height: 45px; - margin-right: 10px; - font-size: 1.3em; - cursor: pointer; -} -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -.import-section-preview { - display : inline-block; - height : 60px; - width: 60px; - border: 1px dashed #999; - border-radius: 3px; -} - -.dialog-section-title { - display : inline-block; - width: 55px; -} - -.import-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - height: 2rem; - word-break : break-all; - vertical-align: middle; - font-style: italic; - font-weight: normal; - text-shadow: none; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding:10px 20px; - font-size:1.5em -} - -.import-button { - font-size: 1em; - height: auto; - padding: 5px 10px; -} - -/************************************************************************************************/ -/* Browse local piskels panel */ -/************************************************************************************************/ - -.local-piskel-list { - width: 100%; -} - -.local-piskel-item { - height: 3em; -} - -.local-piskel-name { - width: 40%; -} - -.local-piskel-save-date { - font-weight : normal; -} - -.local-piskel-list a { - text-decoration: none; -} - -.local-piskel-list a:hover { - text-decoration: underline; -} - -.local-piskel-list-head { - font-weight: bold; - color: gold; -} - -.local-piskel-load-button, -.local-piskel-delete-button { - width : 75px; -} -#dialog-container.create-palette { - width: 500px; - height: 600px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette { - margin-top: -300px; -} - -.create-palette-section { - position: absolute; - left: 10px; - top: 50px; -} - -.create-palette-import-section { - display : inline-block; -} - -.colors-container { - position: absolute; - - left: 10px; - right: 10px; - top: 85px; - - height: 460px; - - border: 1px solid black; - background: #333; -} - -.color-picker-container { - position:absolute; - left : 280px; - top:0; - bottom:0; - right:0; - background: #222; -} - -.create-palette-actions { - position: absolute; - box-sizing: border-box; - - width:100%; - height: 45px; - - left: 0; - right: 0; - bottom: 0; - - padding:10px; - text-align:right; -} - -.color-preview { - width: 170px; - height: 70px; - margin: 11px; -} - -.colors-list { - overflow: auto; - width: 280px; - box-sizing: border-box; - height: 100%; - padding-bottom: 10px; -} - -.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - position:relative; - float : left; - - width : 44px; - height : 44px; - margin : 10px 0 0 10px; - - box-sizing : border-box; - - cursor : pointer; -} - -@-moz-document url-prefix() { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - -@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { - .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ - margin : 7px 0 0 7px; - } -} - - -.create-palette-color { - border:1px solid #2c2c2c; - transition : border-color 0.2s; -} -.create-palette-color:hover { - border:1px solid gold; -} - -.colors-list-drop-proxy { - border:2px dotted #eee; -} - -.create-palette-new-color { - border:2px dotted gold; - - border-radius: 2px; - line-height: 40px; - text-align: center; - font-size: 20px; - color: gold; -} - -.create-palette-color.selected { - border:2px solid gold; -} - -.create-palette-remove-color { - position: absolute; - top: 0; - right: 0; - padding: 2px 4px 0 0; - opacity : 0.2; - - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 1px rgb(0,0,0); - - transition : opacity 0.3s, color 0.1s; -} - -.light-color .create-palette-remove-color { - color: rgb(0,0,0); - text-shadow : 0 0 1px rgb(255,255,255); -} - -.selected .create-palette-remove-color { - top: -1px; - right: -1px; -} - -.create-palette-color:hover .create-palette-remove-color { - opacity: 0.6; -} - -.create-palette-color .create-palette-remove-color:hover { - opacity: 1; - color: rgb(240,80,80); - text-shadow : 0 0 1px rgb(0,0,0); -} - -/*SPECTRUM OVERRIDES*/ - -.create-palette .sp-container{ - background-color: transparent; - border: none; - box-shadow : none; - border-radius:0; - padding:5px; -} -.user-message { - position: absolute; - right: 0; - bottom: 0; - padding: 10px 47px; - max-width: 300px; - - border-top-left-radius: 7px; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - - color: #222; - background-color: #F9EDBE; - - font-weight: bold; - font-size: 13px; - - z-index: 30000; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - - color: gray; - - font-size: 18px; - font-weight: bold; - - cursor: pointer; -} - -.user-message .close:hover { - color: black; -} - -.progress-bar-container { - position: absolute; - left: 0; - bottom: 0; - padding: 10px; - width: 360px; - border-top-right-radius: 2px; - border: gold 2px solid; - border-left: 0; - border-bottom: 0; - background-color: #444; - font-size: 14px; - z-index: 30000; - color: #eee; -} - -.progress-bar-item { - float: left; - height:20px; -} - -.progress-bar-status { - line-height: 20px; - width : 40px; - overflow : hidden; - margin: 0 0 0 10px; -} - -.progress-bar { - border : 1px solid grey; - margin-top: 8px; - height : 4px; - width : 300px; - background : linear-gradient(to left, gold, gold) no-repeat -300px 0; - background-color : black; -} -.toolbox-container { - border: 4px solid #888; - font-size: medium; - color: white; - text-align: left; - border-radius: 4px; - margin-top: 5px; - margin-bottom: 10px; - overflow: hidden; -} - -.toolbox-title { - padding: 8px; - margin: 0; - font-size: 15px; - background: #222; -} - -/** - * Layers container - */ -.layers-list-container { -} - -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - -.layers-title { - position: relative; -} - -.layers-toggle-preview { - position: absolute; - top: 0.3em; - right: 0.5em; - - color: #999; - font-size: 1.3em; - cursor: pointer; - - transition: 0.2s linear; -} - -.layers-toggle-preview:hover { - color: white; -} - -.layers-toggle-preview-enabled, -.layers-toggle-preview-enabled:hover { - color : gold; -} - -.layers-list { - font-size : 12px; -} - -.layer-item { - height:24px; - line-height: 24px; - padding : 0 0 0 10px; - border-top: 1px solid #444; - cursor : pointer; -} - -.layer-item:hover { - background : #222; -} - -.current-layer-item, -.current-layer-item:hover { - background : #333; - color: gold; -} - -.layers-button-container { - overflow : hidden; -} - -.layers-button { - margin: 0; - width: 16.66667%; - float : left; -} - -/* @override */ -.layers-button-container .layers-button { - border-left-width: 0; -} - -.layers-button:last-child { - border-right-width: 0; -} -.palettes-title { - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -} -.palettes-list-colors { - overflow: auto; - max-height: 160px; -} -.palettes-list-color { - cursor: pointer; - float: left; - margin: 0 0 5px 5px; - width: 32px; - height: 32px; - position: relative; -} -.palettes-list-color:nth-child(-n+5) { - margin-top: 5px; -} -.palettes-list-color div { - width: 32px; - height: 32px; -} -.palettes-list-has-scrollbar .palettes-list-color, .palettes-list-has-scrollbar .palettes-list-color div { - width: 29px -} -.palettes-list-primary-color:before, .palettes-list-secondary-color:before { - content: ""; - position: absolute; - bottom: 1px; - display: inline-block; - border: 7px solid gold; - border-top-color: transparent; - width: 0px; - height: 0px; -} -.palettes-list-primary-color:before { - left: 1px; - border-right-color: transparent; -} -.palettes-list-secondary-color:before { - right: 1px; - border-left-color: transparent; -} -.palettes-list-actions { - background-color: #3f3f3f; - border-bottom-color: #222; - height: 24px; - padding: 0; - overflow: hidden; -} - -.palettes-list-button, -.palettes-list-select { - margin: 0; - float: left; -} - -.palettes-list-button { - width: 16.66667%; -} -.palettes-list-select { - width: 66.66667%; - height: 100%; - padding: 0 5px 0 5px; - - border-style: solid; - border-width: 1px 0 1px 0; - - color: #aaa; - font-size : 0.75em; - - /*thanks firefox, you suck*/ - text-align:left; - /*text-shadow:none;*/ - font-weight: normal; - - transition : background-color 0.3s, color 0.3s; - cursor:pointer; -} - -.palettes-list-select:hover { - color: white; - background-color: #484848; -} - -.palettes-list-select:focus { - background-color: #484848; - color: white; - outline: none; -} - -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} -.palettes-list-no-colors { - height: 42px; - width: 100%; - color: grey; - font-size: 0.7em; - font-style: italic; - line-height: 42px; - text-align: center -} - -/** - * Animated preview styles. - */ - -.preview-container { - border : 0 Solid black; - border-radius:5px 0 0 5px; - box-shadow : 0 0 2px rgba(0,0,0,0.2); - font-size: 0; -} - -.preview-container .canvas-container { - overflow : hidden; -} - -.preview-container canvas { - border : 0 Solid transparent; -} - -.canvas-container .animated-preview-canvas-background { - position : relative; - height: 100%; -} - -#animated-preview-container { - background: #333; - border-radius : 0 0 2px 2px; - overflow : hidden; -} - -.canvas-container-wrapper { - height :200px; - width : 200px; - overflow:hidden; -} - -.tiled-frame-container { - height: 100%; - width: 100%; - position: relative; - background-repeat : repeat; -} - -.display-fps { - float: left; - color: #aaa; - font-size: 12px; - min-width: 55px; - vertical-align: bottom; - line-height: 26px; -} - -.range-fps { - overflow: hidden; - width: 100px; - height : 26px; - margin : 0; - box-sizing: border-box; - padding:0; -} - -.preview-toggle-onion-skin { - font-size: 2rem; - color: #aaa; - float: left; - line-height: 26px; - height: 100%; - padding-left: 5px; - padding-right: 5px; - border-right: 1px solid #222; - transition: 0.2s linear; - cursor:pointer; -} - -.preview-toggle-onion-skin:hover { - color : white; -} - -.preview-toggle-onion-skin-enabled, -.preview-toggle-onion-skin-enabled:hover { - color : gold; -} - -.open-popup-preview-button { - position : absolute; - z-index: 500; - right : 10px; - top : 10px; - width : 24px; - height: 18px; - - border : 2px solid white; - background : rgba(0,0,0,0.3); - cursor : pointer; - - opacity: 0; - transition: 0.3s opacity, 0.3s border-color; -} - -.minimap-container:hover .open-popup-preview-button { - opacity: 1; -} - -.open-popup-preview-button:hover { - border-color: gold; -} - - -.transformations-container .tool-icon { - float:left; -} - -/*** -Spectrum Colorpicker v1.1.2 -https://github.com/bgrins/spectrum -Author: Brian Grinstead -License: MIT -***/ - -.sp-container { - position:absolute; - top:0; - left:0; - display:inline-block; - *display: inline; - *zoom: 1; - /* https://github.com/bgrins/spectrum/issues/40 */ - z-index: 9999994; - overflow: hidden; -} -.sp-container.sp-flat { - position: relative; -} - -/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ -.sp-top { - position:relative; - width: 100%; - display:inline-block; -} -.sp-top-inner { - position:absolute; - top:0; - left:0; - bottom:0; - right:0; -} -.sp-color { - position: absolute; - top:0; - left:0; - bottom:0; - right:20%; -} -.sp-hue { - position: absolute; - top:0; - right:0; - bottom:0; - left:84%; - height: 100%; -} -.sp-fill { - padding-top: 80%; -} -.sp-sat, .sp-val { - position: absolute; - top:0; - left:0; - right:0; - bottom:0; -} - -.sp-alpha-enabled .sp-top { - margin-bottom: 18px; -} -.sp-alpha-enabled .sp-alpha { - display: block; -} -.sp-alpha-handle { - position:absolute; - top:-4px; - bottom: -4px; - width: 6px; - left: 50%; - cursor: pointer; - border: 1px solid black; - background: white; - opacity: .8; -} -.sp-alpha { - display: none; - position: absolute; - bottom: -14px; - right: 0; - left: 0; - height: 8px; -} -.sp-alpha-inner { - border: solid 1px #333; -} - -/* Don't allow text selection */ -.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { - -webkit-user-select:none; - -moz-user-select: -moz-none; - -o-user-select:none; - user-select: none; -} - -.sp-container.sp-input-disabled .sp-input-container { - display: none; -} -.sp-container.sp-buttons-disabled .sp-button-container { - display: none; -} -.sp-palette-only .sp-picker-container { - display: none; -} -.sp-palette-disabled .sp-palette-container { - display: none; -} - -.sp-initial-disabled .sp-initial { - display: none; -} - - -/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ -.sp-sat { - background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; - filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); -} -.sp-val { - background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); - background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); - background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); - background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; - filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); -} - -.sp-hue { - background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); - background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); -} - -/* IE filters do not support multiple color stops. - Generate 6 divs, line them up, and do two color gradients for each. - Yes, really. - */ -.sp-1 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); -} -.sp-2 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); -} -.sp-3 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); -} -.sp-4 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); -} -.sp-5 { - height:16%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); -} -.sp-6 { - height:17%; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); -} - -.sp-hidden { - display: none !important; -} - -/* Clearfix hack */ -.sp-cf:before, .sp-cf:after { content: ""; display: table; } -.sp-cf:after { clear: both; } -.sp-cf { *zoom: 1; } - -/* Mobile devices, make hue slider bigger so it is easier to slide */ -@media (max-device-width: 480px) { - .sp-color { right: 40%; } - .sp-hue { left: 63%; } - .sp-fill { padding-top: 60%; } -} -.sp-dragger { - border-radius: 5px; - height: 5px; - width: 5px; - border: 1px solid #fff; - background: #000; - cursor: pointer; - position:absolute; - top:0; - left: 0; -} -.sp-slider { - position: absolute; - top:0; - cursor:pointer; - height: 3px; - left: -1px; - right: -1px; - border: 1px solid #000; - background: white; - opacity: .8; -} - -/* -Theme authors: -Here are the basic themeable display options (colors, fonts, global widths). -See http://bgrins.github.io/spectrum/themes/ for instructions. -*/ - -.sp-container { - border-radius: 0; - background-color: #ECECEC; - border: solid 1px #f0c49B; - padding: 0; -} -.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue -{ - font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; -} -.sp-top -{ - margin-bottom: 3px; -} -.sp-color, .sp-hue -{ - border: solid 1px #666; -} - -/* Input */ -.sp-input-container { - float:right; - width: 100px; - margin-bottom: 4px; -} -.sp-initial-disabled .sp-input-container { - width: 100%; -} -.sp-input { - font-size: 12px !important; - border: 1px inset; - padding: 4px 5px; - margin: 0; - width: 100%; - background:transparent; - border-radius: 3px; - color: #222; -} -.sp-input:focus { - border: 1px solid orange; -} -.sp-input.sp-validation-error -{ - border: 1px solid red; - background: #fdd; -} -.sp-picker-container , .sp-palette-container -{ - float:left; - position: relative; - padding: 10px; - padding-bottom: 300px; - margin-bottom: -290px; -} -.sp-picker-container -{ - width: 172px; - border-left: solid 1px #fff; -} - -/* Palettes */ -.sp-palette-container -{ - border-right: solid 1px #ccc; -} - -.sp-palette .sp-thumb-el { - display: block; - position:relative; - float:left; - width: 24px; - height: 15px; - margin: 3px; - cursor: pointer; - border:solid 2px transparent; -} -.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { - border-color: orange; -} -.sp-thumb-el -{ - position:relative; -} - -/* Initial */ -.sp-initial -{ - float: left; - border: solid 1px #333; -} -.sp-initial span { - width: 30px; - height: 25px; - border:none; - display:block; - float:left; - margin:0; -} - -/* Buttons */ -.sp-button-container { - float: right; -} - -/* Replacer (the little preview div that shows up instead of the ) */ -.sp-replacer { - margin:0; - overflow:hidden; - cursor:pointer; - padding: 4px; - display:inline-block; - *zoom: 1; - *display: inline; - border: solid 1px #91765d; - background: #eee; - color: #333; - vertical-align: middle; -} -.sp-replacer:hover, .sp-replacer.sp-active { - border-color: #F0C49B; - color: #111; -} -.sp-replacer.sp-disabled { - cursor:default; - border-color: silver; - color: silver; -} -.sp-dd { - padding: 2px 0; - height: 16px; - line-height: 16px; - float:left; - font-size:10px; -} -.sp-preview -{ - position:relative; - width:25px; - height: 20px; - border: solid 1px #222; - margin-right: 5px; - float:left; - z-index: 0; -} - -.sp-palette -{ - *width: 220px; - max-width: 220px; -} -.sp-palette .sp-thumb-el -{ - width:16px; - height: 16px; - margin:2px 1px; - border: solid 1px #d0d0d0; -} - -.sp-container -{ - padding-bottom:0; -} - - -/* Buttons: http://hellohappy.org/css3-buttons/ */ -.sp-container button { - background-color: #eeeeee; - background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); - background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); - background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); - background-image: -o-linear-gradient(top, #eeeeee, #cccccc); - background-image: linear-gradient(to bottom, #eeeeee, #cccccc); - border: 1px solid #ccc; - border-bottom: 1px solid #bbb; - border-radius: 3px; - color: #333; - font-size: 14px; - line-height: 1; - padding: 5px 4px; - text-align: center; - text-shadow: 0 1px 0 #eee; - vertical-align: middle; -} -.sp-container button:hover { - background-color: #dddddd; - background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); - background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); - background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); - border: 1px solid #bbb; - border-bottom: 1px solid #999; - cursor: pointer; - text-shadow: 0 1px 0 #ddd; -} -.sp-container button:active { - border: 1px solid #aaa; - border-bottom: 1px solid #888; - -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; - box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; -} -.sp-cancel -{ - font-size: 11px; - color: #d93f3f !important; - margin:0; - padding:2px; - margin-right: 5px; - vertical-align: middle; - text-decoration:none; - -} -.sp-cancel:hover -{ - color: #d93f3f !important; - text-decoration: underline; -} - - -.sp-palette span:hover, .sp-palette span.sp-thumb-active -{ - border-color: #000; -} - -.sp-preview, .sp-alpha, .sp-thumb-el -{ - position:relative; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); -} -.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner -{ - display:block; - position:absolute; - top:0;left:0;bottom:0;right:0; -} - -.sp-palette .sp-thumb-inner -{ - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); -} - -.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner -{ - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); -} - -/** - * Piskel specific CSS for spectrum widgets - */ - -/* Widget's main container */ -.sp-container { - border-radius: 4px; - background-color: #2B2B2B; - border: solid 4px #888; - padding: 5px 5px 0 5px; - box-shadow : 0 0 5px 0 black; -} - -.sp-container[data-y-position=bottom] { - border-top-left-radius: 0; -} - -.sp-container[data-y-position=top] { - border-bottom-left-radius: 0; -} - -/* Color square container */ -.sp-color, .sp-hue { - border : 1px solid #222; -} - -/* Remove the padding on the input container */ -.sp-replacer { - padding: 4px; - height: 100%; - border-width: 0; - box-sizing: border-box; - -moz-box-sizing:border-box; - background-color: #444; -} - -.sp-replacer:hover { - background-color: #888; -} - -/* Hide the triangle */ -.sp-dd { - display: none; -} - -/* */ -.sp-preview { - margin-right: 0; - height: 100%; - width: 39px; - border-width: 0; -} - -.sp-palette-row-selection { - max-width: 62px; -} - -.sp-palette .sp-thumb-el { - margin : 0 5px 5px 0; - width: 24px; - height: 24px; - border-color: #444; - -} - -.sp-picker-container, .sp-palette-container { - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - border-left-width: 0; - border-right-width: 0; -} - -.sp-picker-container { - padding: 5px; - padding-bottom: 300px; - margin-bottom: -295px; -} - -.sp-slider { - height: 5px; - left: -2px; - right: -2px; - border: 2px solid white; - background: rgba(255,255,255,0); - opacity: 1; - border-radius: 2px; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-dragger { - border-radius: 8px; - height: 12px; - width: 12px; - border: 2px solid white; - background: none; - box-sizing:border-box; - -moz-box-sizing:border-box; - box-shadow: 0 0 1px 1px rgba(0,0,0,0.5), inset 0 0 1px 1px rgba(0,0,0,0.5); -} - -.sp-palette .sp-thumb-el.sp-thumb-active { - border-color: gold; - box-shadow: 0 0 0px 1px gold; -} - -.sp-input { - border: 1px solid #666; - margin: 0; - background: #111; - border-radius: 2px; - color: #D3D3D3; - font-family: Courier!important; -} - -.sp-input.sp-validation-error { - background: #330000; -} -/*! - * Bootstrap v2.1.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.tooltip { - position: absolute; - z-index: 30000; - display: block; - visibility: visible; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); -} -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} -.tooltip.top { - margin-top: -3px; -} -.tooltip.right { - margin-left: 3px; -} -.tooltip.bottom { - margin-top: 3px; -} -.tooltip.left { - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000000; -} - -.tooltip { - line-height: 20px; -} - -.tooltip.in { - opacity: 0.95; - filter: alpha(opacity=95); -} - -.tooltip { - line-height: 20px; -} -.preview-list-wrapper { - position: relative; - height: 100%; - overflow: hidden; -} - -.preview-list-scroller { - overflow-y: scroll; - overflow-x: hidden; - height: 100%; -} - -.top-overflow, -.bottom-overflow { - height: 20px; - position: absolute; - left: 0; - right: 12px; - - -webkit-transition: all 500ms ease-out; - -moz-transition: all 500ms ease-out; - -ms-transition: all 500ms ease-out; - -o-transition: all 500ms ease-out; - transition: all 500ms ease-out; - - background-image: linear-gradient(45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)), - linear-gradient(-45deg, rgba(0,0,0, 0.8) 25%, transparent 25%, transparent 75%, rgba(0,0,0, 0.8) 75%, rgba(0,0,0, 0.8)); - background-size: 29px 45px; - background-repeat: repeat-x; - background-position-x: 3px; - z-index: 10; -} - -.top-overflow { - top: -20px; -} - -.bottom-overflow { - bottom: -20px; - background-position-x: 0; - background-position-y: -23px; -} - -.top-overflow-visible .top-overflow { - top: 0; -} - -.bottom-overflow-visible .bottom-overflow { - bottom: 0; -} - -.preview-list { - list-style-type: none; - padding-right: 7px; -} - -.add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; - margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; - background-color: #222; -} - -.add-frame-action .label { - width: 80px; - margin: 0 auto; -} - -.add-frame-action:hover { - border-color: gold; -} - -.preview-tile { - position: relative; - border: #444 3px solid; - border-radius: 3px; - margin: 5px 0; - width: 96px; - height: 96px; -} - -.preview-tile:first-child { - margin-top: 0; -} - -.preview-tile:hover { - border: #999 3px solid; -} - -.tile-view { - position : relative; -} - -.preview-tile .tile-overlay { - z-index: 10; - position: absolute; - background-color: rgba(100, 100, 100, 0.6); - opacity: 0; - height: 30px; - width: 30px; - border: none; -} - -.preview-tile:hover .tile-overlay { - opacity: 1.0; -} - -.preview-tile .tile-overlay.tile-count { - display: block; - opacity: 1.0; - border-bottom-right-radius: 3px; - top: 0; - left: 0; - font-size: 14px; - line-height: 30px; - color: white; - font-weight: bold; - text-align: center; - cursor: default; -} - -.preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; - top: 0; - right: 0; - border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.duplicate-frame-action { - bottom: 0; - right: 0; - border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: pointer; -} - -.preview-tile .tile-overlay.dnd-action { - bottom: 0; - left: 0; - border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; - cursor: move; -} - -.preview-tile.selected { - border-color: gold; -} - -.preview-tile.selected:after { - content: " "; - position: absolute; - top: 38px; - right: -15px; - border: transparent 4px solid; - border-left-color: gold; - border-width: 6px; - border-style: solid; -} - - -/** - * Drag n drop styles. - */ - -.preview-tile-drop-proxy { - border: 3px dashed gold; - height: 90px; - border-radius: 9px; - background-color: rgba(255, 215,0, 0.2); -} - -.minimap-crop-frame { - position:absolute; - border:1px solid rgba(255,255,255,0.5); - z-index:100; - box-sizing : border-box; - -moz-box-sizing : border-box; - cursor : pointer; -} \ No newline at end of file diff --git a/css/piskel-style-packaged-2015-09-14-10-01.css b/css/piskel-style-packaged-2016-01-14-12-02.css similarity index 83% rename from css/piskel-style-packaged-2015-09-14-10-01.css rename to css/piskel-style-packaged-2016-01-14-12-02.css index 32d12920..5f614827 100644 --- a/css/piskel-style-packaged-2015-09-14-10-01.css +++ b/css/piskel-style-packaged-2016-01-14-12-02.css @@ -107,9 +107,40 @@ body { margin-left: 0; } +/** + * TOOLTIPS + */ .tooltip-shortcut { color:gold; } + +.tooltip-container { + text-align: left; +} + +.tooltip-descriptor { + color:#999; +} + +.tooltip-descriptor:last-child { + padding-bottom: 5px; +} + +.tooltip-descriptor-button { + padding: 2px; + border: 1px Solid #999; + font-size: 0.8em; + margin-right: 5px; + width: 35px; + text-align: center; + border-radius: 3px; + display: inline-block; + line-height: 10px; +} +@keyframes fade { + 50% { opacity: 0.5; } +} + /** * Application layout */ @@ -215,22 +246,22 @@ body { .light-picker-background, .light-canvas-background .canvas-background { - background: url(../img/canvas_background/light_canvas_background.png) repeat; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABlBMVEXf39////8zI3BgAAAAHklEQVR4AWNghAIGCMDgjwgFCDDSw2M0PSCD0fQAACRcAgF4ciGUAAAAAElFTkSuQmCC') repeat; } .medium-picker-background, .medium-canvas-background .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABlBMVEW6urr///82MBGFAAAAHUlEQVR4AWOAAUYoQOePEAUj3v9oYDQ9gMBoegAAJFwCAbLaTIMAAAAASUVORK5CYII=') repeat; } .lowcont-medium-picker-background, .lowcont-medium-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABlBMVEXV1dXb29tFGkCIAAAAHklEQVR4AWNghAIGCMDgjwgFCDDSw2M0PSCD0fQAACRcAgF4ciGUAAAAAElFTkSuQmCC') repeat; } .lowcont-dark-picker-background, .lowcont-dark-canvas-background .canvas-background { - background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABlBMVEVMTExVVVUnhsEkAAAAHUlEQVR4AWOAAUYoQOePEAUj3v9oYDQ9gMBoegAAJFwCAbLaTIMAAAAASUVORK5CYII=') repeat; } .canvas.onion-skin-canvas { @@ -468,55 +499,6 @@ body { margin-right: 0; } -/********************************************************** *j* j** j*j j j j** *****************/ -/* Settings icons I I I I I\I \ */ -/********************************************************** *** *** *** * * '** *****************/ - -.tool-icon.gallery-icon { - background-image: url(../img/gallery.png); - background-position: 3px 3px; - background-size: 39px 39px; -} - -.tool-icon.resize-icon { - background-image: url(../img/resize-icon.png); - background-position: 10px 10px; - background-size: 26px 26px; -} - -.tool-icon.save-icon { - background-image: url(../img/save.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.gear-icon { - background-image: url(../img/gear.png); - background-position: 6px 7px; - background-size: 32px 32px; -} - -.tool-icon.export-icon { - background-image: url(../img/export.png); - background-position: 7px 5px; - background-size: 36px 36px; - position: relative; -} - -.tool-icon.local-storage-icon { - background-image: url(../img/local-storage-icon.png); - background-position: 10px 12px; - background-size: 30px; - position: relative; -} - -.tool-icon.import-icon { - background-image: url(../img/import-icon.png); - background-position: 10px 5px; - background-size: 26px; - position: relative; -} - .tool-icon .label { position: absolute; left: 0; @@ -579,7 +561,6 @@ body { .settings-description { margin : 0 0 10px 0; - display : inline-block; } .settings-form-section { @@ -594,42 +575,6 @@ body { vertical-align: middle; } -/************************************************************************************************/ -/* Save panel */ -/************************************************************************************************/ - -.anonymous .save-public-section, -.anonymous #save-online-button { - display : none; -} - -.save-field { - width: 100%; -} - -.save-status { - margin-top: 10px; - margin-bottom: -10px; - vertical-align: middle; - font-weight: normal; - text-shadow: none; - font-style: italic; -} - -.save-file-name { - white-space: nowrap; - font-weight: bold; - color: white; - font-style: normal; -} - -.save-desktop-file-name { - word-wrap: break-word; - font-weight: bold; - color: white; - font-style: normal; -} - /*******************************/ /* Application Setting panel */ /*******************************/ @@ -749,6 +694,28 @@ body { background: rgba(0,0,0,0.5); color: white; } + +.scaling-factor { + margin-bottom: 10px; +} + +.scaling-factor-input { + margin: 5px; + vertical-align: middle; + width: 145px; +} + +.scaling-factor-text { + height: 31px; + display: inline-block; + line-height: 30px; + width: 40px; + border: 1px solid grey; + box-sizing: border-box; + border-radius: 3px; + text-align: center; +} + /************************************************************************************************/ /* Import panel */ /************************************************************************************************/ @@ -813,6 +780,10 @@ body { border-color: #555 !important; } +.resize-origin-option:hover { + border : 3px solid white; +} + .resize-origin-option.selected { border : 3px solid gold; } @@ -870,6 +841,33 @@ body { border-left-color: gold; margin-top: -4px; } +.save-field { + width: 100%; +} + +.save-status { + margin-top: 10px; + margin-bottom: -10px; + vertical-align: middle; + font-weight: normal; + text-shadow: none; + font-style: italic; +} + +.save-file-name { + white-space: nowrap; + font-weight: bold; + color: white; + font-style: normal; +} + +.save-desktop-file-name { + word-wrap: break-word; + font-weight: bold; + color: white; + font-style: normal; +} + .tool-icon { position : relative; cursor : pointer; @@ -877,9 +875,6 @@ body { height: 46px; margin: 1px; background-color: #3a3a3a; - background-repeat: no-repeat; - background-position: 12px 12px; - background-size: 24px 24px; } .tool-icon.selected { @@ -894,161 +889,77 @@ body { width : 100%; border: 3px solid gold; box-sizing: border-box; - -moz-box-sizing: border-box; } .tool-icon:hover { background-color: #444; } -/* - * Tool icons: - */ -.tool-icon.tool-pen { - background-image: url(../img/tools/pen.png); -} - -.tool-icon.tool-vertical-mirror-pen { - background-image: url(../img/tools/mirror.png); - background-position: 0px 10px; - background-size: 38px 27px; -} - -.tool-icon.tool-paint-bucket { - background-image: url(../img/tools/paintbucket.png); -} - -.tool-icon.tool-eraser { - background-image: url(../img/tools/eraser.png); -} - -.tool-icon.tool-stroke { - background-image: url(../img/tools/stroke.png); -} - -.tool-icon.tool-rectangle { - background-image: url(../img/tools/rectangle.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-circle { - background-image: url(../img/tools/circle.png); -} - -.tool-icon.tool-move { - background-image: url(../img/tools/hand.png); - background-size: 24px 24px; -} - -.tool-icon.tool-rectangle-select { - background-image: url(../img/tools/rectangle_selection.png); - background-position: 12px 14px; - background-size: 24px 20px; -} - -.tool-icon.tool-shape-select { - background-image: url(../img/tools/magicwand.png); -} - -.tool-icon.tool-lighten { - background-image: url(../img/tools/lighten.png); - background-position: 8px 8px; - background-size: 30px 30px; -} - -.tool-icon.tool-colorpicker { - background-image: url(../img/tools/eyedropper.png); - background-size: 23px 23px; -} - -.tool-icon.tool-colorswap { - background-image: url(../img/tools/swap-colors.png); - background-position: 6px 6px; - background-size: 36px 36px; -} - -.tool-icon.tool-flip { - background-image: url(../img/tools/flip.png); - background-position: 7px 11px; - background-size: 32px; -} - -.tool-icon.tool-rotate { - background-image: url(../img/tools/rotate.png); - background-position: 10px 9px; - background-size: 26px; -} - -.tool-icon.tool-clone { - background-image: url(../img/tools/clone.png); - background-position: 9px 15px; - background-size: 30px; -} - /* * Tool cursors: */ .tool-paint-bucket .drawing-canvas-container:hover, .tool-colorswap .drawing-canvas-container:hover { - cursor: url(../img/icons/paint-bucket.png) 12 12, pointer; + cursor: url(../img/cursors/paint-bucket.png) 12 12, pointer; } .tool-vertical-mirror-pen .drawing-canvas-container:hover { - cursor: url(../img/icons/vertical-mirror-pen.png) 5 15, pointer; + cursor: url(../img/cursors/vertical-mirror-pen.png) 5 15, pointer; } .tool-pen .drawing-canvas-container:hover, -.tool-lighten .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; +.tool-lighten .drawing-canvas-container:hover, +.tool-dithering .drawing-canvas-container:hover { + cursor: url(../img/cursors/pen.png) 0 15, pointer; } .tool-eraser .drawing-canvas-container:hover { - cursor: url(../img/icons/eraser.png) 0 15, pointer; + cursor: url(../img/cursors/eraser.png) 0 15, pointer; } .tool-stroke .drawing-canvas-container:hover { - cursor: url(../img/icons/pen.png) 0 15, pointer; + cursor: url(../img/cursors/pen.png) 0 15, pointer; } .tool-rectangle .drawing-canvas-container:hover { - cursor: url(../img/icons/rectangle.png) 0 15, pointer; + cursor: url(../img/cursors/rectangle.png) 0 15, pointer; } .tool-circle .drawing-canvas-container:hover { - cursor: url(../img/icons/circle.png) 2 15, pointer; + cursor: url(../img/cursors/circle.png) 2 15, pointer; } .tool-move .drawing-canvas-container:hover { - cursor: url(../img/icons/hand.png) 7 7, pointer; + cursor: url(../img/cursors/hand.png) 7 7, pointer; } -.tool-rectangle-select .drawing-canvas-container:hover { +.tool-rectangle-select .drawing-canvas-container:hover, +.tool-lasso-select .drawing-canvas-container:hover { cursor: crosshair; } .tool-shape-select .drawing-canvas-container:hover { - cursor: url(../img/icons/wand.png) 15 15, pointer; + cursor: url(../img/cursors/wand.png) 15 15, pointer; } .tool-colorpicker .drawing-canvas-container:hover { - cursor: url(../img/icons/dropper.png) 0 15, pointer; + cursor: url(../img/cursors/dropper.png) 0 15, pointer; } -.swap-colors-icon { - background-image: url(../img/tools/swap-arrow-square-small-grey.png); +.swap-colors-button { position: relative; top: 50px; left: 6px; height: 18px; width: 18px; - background-size: 18px; + opacity : 0.3; + cursor : pointer; } -.swap-colors-icon:hover { +.swap-colors-button:hover { opacity : 1; } @@ -1118,162 +1029,254 @@ body { ); } -.tools-tooltip-container { - text-align: left; - padding-bottom: 5px; -} -.tools-tooltip-descriptor { - color:#999; -} - -.tools-tooltip-descriptor-button { - padding:2px; - border:1px Solid #999; - font-size:0.8em; - margin-right:5px; - width:35px; - text-align:center; - border-radius:3px; - display:inline-block; - line-height: 10px; -} - - -.action-icon { - cursor: pointer; - height: 100%; - background-repeat: no-repeat; - background-position: 50%; -} - -.edit-icon { - background-image: url('../img/tools/pen.png'); - background-repeat: no-repeat; -} - -.merge-icon { - background-image: url('../img/merge-icon.png'); - background-repeat: no-repeat; -} - -.plus-icon { - font-size:15px; - text-align:center; -} - -.delete-icon { -} -.cheatsheet-link { - position: fixed; - bottom: 10px; - left: 10px; - - padding: 1px 0 0 45px; - color : gold; - font-weight: bold; - font-size : 1.25em; - line-height: 20px; - - cursor : pointer; - - background-image:url('../img/keyboard.png'); - background-size:35px 20px; - background-repeat:no-repeat; - opacity: 0.5; - z-index: 11000; - transition : opacity 0.3s; -} - -.cheatsheet-link:hover { - opacity: 1; -} - -#cheatsheet-wrapper { - position: absolute; - z-index: 10000; - - top: 50px; - right: 50px; - bottom: 50px; - left: 50px; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - color: white; -} - -.cheatsheet-container { - width: 100%; - height: 100%; - - box-sizing: border-box; - -moz-box-sizing : border-box; - - padding: 20px 3%; - border-radius: 3px; - background: rgba(0,0,0,0.9); - overflow: auto; -} - -.cheatsheet-container .cheatsheet-title { - font-size:24px; - margin-top: 0; -} - -.cheatsheet-container .cheatsheet-title:nth-of-type(2) { - margin-top: 30px; -} - -.cheatsheet-section { - float: left; - width : 33%; -} - -.cheatsheet-shortcut { +.pen-size-container { overflow: hidden; - margin: 10px 0; + padding: 5px 5px; } -.cheatsheet-icon.tool-icon { +.pen-size-option { float: left; - display: inline-block; - - height: 30px; - width: 30px; - margin: 0 20px 0 0; - - background-size: 20px 20px; - background-position: 5px 5px; -} - -.cheatsheet-description { - font-family:Courier; - color: white; - font-size : 13px; - margin-left: 20px; - line-height : 30px; -} - -.cheatsheet-key { - display : inline-block; - height: 30px; - line-height: 30px; - padding: 0 10px; - - border : 1px solid gold; - border-radius: 2px; - box-sizing: border-box; - -moz-box-sizing : border-box; - - text-align: center; - font-family:Courier; - font-weight: bold; - font-size : 18px; - color: gold; + width: 20px; + height: 20px; + margin-right: 2px; + border-style: solid; + border-width: 2px; + border-color: #444; + cursor: pointer; } + +.pen-size-option[data-size='1'] { + padding: 6px; +} +.pen-size-option[data-size='2'] { + padding: 5px; +} +.pen-size-option[data-size='3'] { + padding: 4px; +} +.pen-size-option[data-size='4'] { + padding: 3px; +} + +.pen-size-option:before { + content: ''; + width: 100%; + height: 100%; + background-color: white; + display: block; +} + +.pen-size-option:hover { + border-color: #888; +} + +.pen-size-option.selected:before { + background-color: gold; +} + +.pen-size-option.selected { + border-color: gold; +} +/* +Icon classes can be used entirely standalone. They are named after their original file names. + +```html + +
+ + + +``` +*/ +.icon-common-keyboard-gold { + background-image: url(../img/icons.png); + background-position: -230px 0px; + width: 35px; + height: 20px; +} +.icon-common-swapcolors-arrow-grey { + background-image: url(../img/icons.png); + background-position: -230px -46px; + width: 18px; + height: 18px; +} +.icon-frame-dragndrop-white { + background-image: url(../img/icons.png); + background-position: -198px -184px; + width: 30px; + height: 30px; +} +.icon-frame-duplicate-white { + background-image: url(../img/icons.png); + background-position: -168px -184px; + width: 30px; + height: 30px; +} +.icon-frame-plus-white { + background-image: url(../img/icons.png); + background-position: -230px -20px; + width: 26px; + height: 26px; +} +.icon-frame-recyclebin-white { + background-image: url(../img/icons.png); + background-position: -138px -184px; + width: 30px; + height: 30px; +} +.icon-minimap-popup-preview-arrow-gold { + background-image: url(../img/icons.png); + background-position: -230px -82px; + width: 18px; + height: 18px; +} +.icon-minimap-popup-preview-arrow-white { + background-image: url(../img/icons.png); + background-position: -230px -64px; + width: 18px; + height: 18px; +} +.icon-settings-export-white { + background-image: url(../img/icons.png); + background-position: -92px -92px; + width: 46px; + height: 46px; +} +.icon-settings-gear-white { + background-image: url(../img/icons.png); + background-position: -138px 0px; + width: 46px; + height: 46px; +} +.icon-settings-open-folder-white { + background-image: url(../img/icons.png); + background-position: -138px -46px; + width: 46px; + height: 46px; +} +.icon-settings-resize-white { + background-image: url(../img/icons.png); + background-position: -138px -92px; + width: 46px; + height: 46px; +} +.icon-settings-save-white { + background-image: url(../img/icons.png); + background-position: 0px -138px; + width: 46px; + height: 46px; +} +.icon-tool-circle { + background-image: url(../img/icons.png); + background-position: -46px -138px; + width: 46px; + height: 46px; +} +.icon-tool-colorpicker { + background-image: url(../img/icons.png); + background-position: -92px -138px; + width: 46px; + height: 46px; +} +.icon-tool-colorswap { + background-image: url(../img/icons.png); + background-position: 0px 0px; + width: 46px; + height: 46px; +} +.icon-tool-dithering { + background-image: url(../img/icons.png); + background-position: -184px 0px; + width: 46px; + height: 46px; +} +.icon-tool-eraser { + background-image: url(../img/icons.png); + background-position: -184px -46px; + width: 46px; + height: 46px; +} +.icon-tool-lasso-select { + background-image: url(../img/icons.png); + background-position: -184px -92px; + width: 46px; + height: 46px; +} +.icon-tool-lighten { + background-image: url(../img/icons.png); + background-position: -184px -138px; + width: 46px; + height: 46px; +} +.icon-tool-move { + background-image: url(../img/icons.png); + background-position: 0px -184px; + width: 46px; + height: 46px; +} +.icon-tool-paint-bucket { + background-image: url(../img/icons.png); + background-position: -46px -184px; + width: 46px; + height: 46px; +} +.icon-tool-pen { + background-image: url(../img/icons.png); + background-position: -92px -184px; + width: 46px; + height: 46px; +} +.icon-tool-rectangle-select { + background-image: url(../img/icons.png); + background-position: -138px -138px; + width: 46px; + height: 46px; +} +.icon-tool-rectangle { + background-image: url(../img/icons.png); + background-position: -46px -92px; + width: 46px; + height: 46px; +} +.icon-tool-shape-select { + background-image: url(../img/icons.png); + background-position: 0px -92px; + width: 46px; + height: 46px; +} +.icon-tool-stroke { + background-image: url(../img/icons.png); + background-position: -92px -46px; + width: 46px; + height: 46px; +} +.icon-tool-vertical-mirror-pen { + background-image: url(../img/icons.png); + background-position: -92px 0px; + width: 46px; + height: 46px; +} +.icon-tool-clone { + background-image: url(../img/icons.png); + background-position: -46px -46px; + width: 46px; + height: 46px; +} +.icon-tool-flip { + background-image: url(../img/icons.png); + background-position: 0px -46px; + width: 46px; + height: 46px; +} +.icon-tool-rotate { + background-image: url(../img/icons.png); + background-position: -46px 0px; + width: 46px; + height: 46px; +} + .color-picker-slider * { box-sizing: border-box; } @@ -1402,7 +1405,7 @@ body { } #dialog-container-wrapper.animated { - transition: opacity 0.5s; + transition: opacity 0.2s; } #dialog-container-wrapper.show { @@ -1425,10 +1428,6 @@ body { overflow: auto; } -.animated #dialog-container { - transition:margin-top 0.5s; -} - .show #dialog-container { margin-top: 0; } @@ -1451,6 +1450,14 @@ body { position : relative; } +.dialog-content { + position: absolute; + top: 45px; + bottom: 0; + width: 100%; + box-sizing: border-box; +} + .dialog-head { width: 100%; background: gold; @@ -1458,6 +1465,7 @@ body { padding: 10px; color: black; font-size: 1.8em; + height: 45px; box-sizing: border-box; -moz-box-sizing: border-box; } @@ -1471,107 +1479,6 @@ body { font-size: 1.3em; cursor: pointer; } -/************************************************************************************************/ -/* Import dialog */ -/************************************************************************************************/ - -#dialog-container.import-image { - width: 550px; - height: 360px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.import-image { - margin-top: -150px; -} - -.import-subsection { - margin-left: 25px; -} - -.import-section:not(.import-subsection) > .dialog-section-title { - width: 50px; -} - -.import-section-preview-title { - position: absolute; - margin-left: 50%; - margin-top: -28px; -} - -.import-section-preview { - position: absolute; - display: inline-block; - border: 1px dashed #999; - border-radius: 3px; - margin-left: 50%; -} - -.import-section-preview img { - max-width: 220px; - max-height: 220px; - display: block; -} - -.import-section-preview.no-border { - border-color: transparent; -} - -.import-section-preview canvas { - position: absolute; - left: 0; - top: 0; -} - -.dialog-section-title { - display : inline-block; - width: 80px; -} - -.dialog-section-radio { - margin-top: 15px; - vertical-align: sub; -} - -.import-size-field:nth-of-type(2) { - margin-left: 5px; -} - -.import-image-file-name { - display: inline-block; - overflow: hidden; - - width: 200px; - vertical-align: middle; - - word-break : break-all; - white-space: nowrap; - text-overflow: ellipsis; - - font-style: italic; - font-weight: normal; - text-shadow: none; - color: gold; -} - -[name=smooth-resize-checkbox] { - margin : 0 8px; -} - -.dialog-import-body { - padding: 10px 20px; - font-size:1.3em -} - -.import-button { - font-size: 1em; - height: 28px; - padding: 0px 10px; - margin-top: 15px; -} /************************************************************************************************/ /* Browse local piskels panel */ @@ -1610,6 +1517,234 @@ body { .local-piskel-delete-button { width : 75px; } +.cheatsheet-link { + position: fixed; + bottom: 10px; + left: 10px; + + color : gold; + font-weight: bold; + font-size : 1.25em; + line-height: 20px; + + cursor: pointer; + + opacity: 0.5; + z-index: 11000; + transition : opacity 0.3s; +} + +.cheatsheet-link:hover { + opacity: 1; +} + +.cheatsheet-container { + box-sizing: border-box; + display: block; + + bottom: 46px; + padding: 20px 3%; + border-radius: 3px; + background-color: rgba(0,0,0,0.9); + overflow: auto; +} + +.cheatsheet-container .cheatsheet-title { + font-size:24px; + margin-top: 30px; +} + +.cheatsheet-container .cheatsheet-title:nth-of-type(1) { + margin-top: 0; +} + +.cheatsheet-section { + box-sizing: border-box; + float: left; + + vertical-align: top; + padding : 0 20px 20px 20px; + min-width: 300px; +} + +.cheatsheet-boxes { + display: flex; + flex-direction: row; + flex-wrap: wrap; + + float: left; +} + +@media (min-width: 1300px) { + .cheatsheet-container > div { + width: 33%; + } + .cheatsheet-boxes { + flex-direction: column; + } +} + +.cheatsheet-shortcut { + overflow: hidden; + margin: 10px 0; +} + +.cheatsheet-icon.tool-icon { + float: left; + + height: 30px; + width: 30px; + margin: 0 10px 0 0; + background-size: 30px 30px; +} + +.cheatsheet-description { + color: white; + font-size : 14px; + margin-left: 10px; + line-height : 30px; +} + +.cheatsheet-key { + box-sizing: border-box; + display : inline-block; + height: 30px; + line-height: 26px; + padding: 0 10px; + + border : 2px solid white; + border-radius: 2px; + + text-align: center; + font-family:Courier; + font-weight: bold; + font-size : 18px; + color: white; +} + +.cheatsheet-shorcut-conflict .cheatsheet-key { + border-color: red; + color: red; +} + +.cheatsheet-shortcut-editable { + cursor : pointer; +} + +.cheatsheet-shortcut-editable .cheatsheet-key { + border-color: gold; + color: gold; +} + +.cheatsheet-shortcut-editing .cheatsheet-key { + animation: fade .5s infinite; +} + +.cheatsheet-shortcut-undefined .cheatsheet-key { + border-color: red; + color: red; +} + +/*Cheatsheet actions*/ + +.cheatsheet-actions { + position: absolute; + box-sizing: border-box; + + bottom : 0; + left : 0; + right : 0; + height : 46px; + + padding : 10px; + overflow: hidden; + + background-color : gold; +} + +.cheatsheet-helptext { + font-size: 14px; + height : 26px; + line-height : 26px; + color: black; +} + +.cheatsheet-helptext-tooltip { + text-align: left; +} + +.cheatsheet-helptext-tooltip-item { + line-height: 0.9em; + margin: 10px 0; +} + +.cheatsheet-button { + position: absolute; + bottom: 10px; + right: 10px; +} + + +.cheatsheet-icon-tool-circle { + background-image: url(../img/icons/tools/tool-circle.png); +} + +.cheatsheet-icon-tool-colorpicker { + background-image: url(../img/icons/tools/tool-colorpicker.png); +} + +.cheatsheet-icon-tool-colorswap { + background-image: url(../img/icons/tools/tool-colorswap.png); +} + +.cheatsheet-icon-tool-dithering { + background-image: url(../img/icons/tools/tool-dithering.png); +} + +.cheatsheet-icon-tool-eraser { + background-image: url(../img/icons/tools/tool-eraser.png); +} + +.cheatsheet-icon-tool-lasso-select { + background-image: url(../img/icons/tools/tool-lasso-select.png); +} + +.cheatsheet-icon-tool-lighten { + background-image: url(../img/icons/tools/tool-lighten.png); +} + +.cheatsheet-icon-tool-move { + background-image: url(../img/icons/tools/tool-move.png); +} + +.cheatsheet-icon-tool-paint-bucket { + background-image: url(../img/icons/tools/tool-paint-bucket.png); +} + +.cheatsheet-icon-tool-pen { + background-image: url(../img/icons/tools/tool-pen.png); +} + +.cheatsheet-icon-tool-rectangle-select { + background-image: url(../img/icons/tools/tool-rectangle-select.png); +} + +.cheatsheet-icon-tool-rectangle { + background-image: url(../img/icons/tools/tool-rectangle.png); +} + +.cheatsheet-icon-tool-shape-select { + background-image: url(../img/icons/tools/tool-shape-select.png); +} + +.cheatsheet-icon-tool-stroke { + background-image: url(../img/icons/tools/tool-stroke.png); +} + +.cheatsheet-icon-tool-vertical-mirror-pen { + background-image: url(../img/icons/tools/tool-vertical-mirror-pen.png); +} + #dialog-container.create-palette { width: 500px; height: 600px; @@ -1779,6 +1914,107 @@ body { border-radius:0; padding:5px; } +/************************************************************************************************/ +/* Import dialog */ +/************************************************************************************************/ + +#dialog-container.import-image { + width: 550px; + height: 360px; + top : 50%; + left : 50%; + position : absolute; + margin-left: -250px; +} + +.show #dialog-container.import-image { + margin-top: -150px; +} + +.import-subsection { + margin-left: 25px; +} + +.import-section:not(.import-subsection) > .dialog-section-title { + width: 50px; +} + +.import-section-preview-title { + position: absolute; + margin-left: 50%; + margin-top: -28px; +} + +.import-section-preview { + position: absolute; + display: inline-block; + border: 1px dashed #999; + border-radius: 3px; + margin-left: 50%; +} + +.import-section-preview img { + max-width: 220px; + max-height: 220px; + display: block; +} + +.import-section-preview.no-border { + border-color: transparent; +} + +.import-section-preview canvas { + position: absolute; + left: 0; + top: 0; +} + +.dialog-section-title { + display : inline-block; + width: 80px; +} + +.dialog-section-radio { + margin-top: 15px; + vertical-align: sub; +} + +.import-size-field:nth-of-type(2) { + margin-left: 5px; +} + +.import-image-file-name { + display: inline-block; + overflow: hidden; + + width: 200px; + vertical-align: middle; + + word-break : break-all; + white-space: nowrap; + text-overflow: ellipsis; + + font-style: italic; + font-weight: normal; + text-shadow: none; + color: gold; +} + +[name=smooth-resize-checkbox] { + margin : 0 8px; +} + +.dialog-import-body { + padding: 10px 20px; + font-size:1.3em +} + +.import-button { + font-size: 1em; + height: 28px; + padding: 0px 10px; + margin-top: 15px; +} .user-message { position: absolute; right: 0; @@ -1877,13 +2113,6 @@ body { .layers-list-container { } -/*.layers-title { - background-image: url('../img/layers.svg'); - background-size: 22px; - background-repeat: no-repeat; - background-position: 97%; -}*/ - .layers-title { position: relative; } @@ -1983,7 +2212,6 @@ body { border-radius: 0 0 0 2px; } - .palettes-list-color:nth-child(1):after { content: "1"; } @@ -2015,6 +2243,7 @@ body { .palettes-list-color:nth-child(-n+5) { margin-top: 5px; } + .palettes-list-color div { width: 32px; height: 32px; @@ -2088,10 +2317,6 @@ body { outline: none; } -.palettes-list-actions .edit-icon { - background-size: 15px; - background-position: 50%; -} .palettes-list-no-colors { height: 42px; width: 100%; @@ -2225,17 +2450,20 @@ body { } .open-popup-preview-button { - width : 18px; - height: 18px; - border : 2px solid white; - background-image: url(../img/popup-preview-arrow-white.png); background-color : rgba(0,0,0,0.3); } .open-popup-preview-button:hover { border-color: gold; - background-image: url(../img/popup-preview-arrow-gold.png); +} + +/** + * The regular image is provided bby the sprite icons.png+icons.css + */ +.icon-minimap-popup-preview-arrow-white:hover { + background-image: url(../img/icons/minimap/minimap-popup-preview-arrow-gold.png); + background-position: 0 0; } @@ -3017,24 +3245,28 @@ See http://bgrins.github.io/spectrum/themes/ for instructions. } .add-frame-action { - border: #888 solid 4px; - font-size: 13px; - color: #888; - cursor: pointer; - padding: 6px 0; - border-radius: 4px; margin-top: 8px; - background-image: url(../img/plus.png); - background-repeat: no-repeat; - background-position: 3px 7px; - background-size: 26px 26px; - text-indent: 18px; + padding: 6px 0; + overflow: hidden; + width: 96px; + + border: #888 solid 3px; + border-radius: 4px; + + color: #888; background-color: #222; + font-size: 13px; + cursor: pointer; +} + +.add-frame-action-icon { + margin: 3px; + float: left; } .add-frame-action .label { - width: 80px; - margin: 0 auto; + overflow: hidden; + text-align: left; } .add-frame-action:hover { @@ -3091,15 +3323,9 @@ See http://bgrins.github.io/spectrum/themes/ for instructions. } .preview-tile .tile-overlay.delete-frame-action { - background-image: url(../img/garbage.png); - background-repeat: no-repeat; top: 0; right: 0; border-bottom-left-radius: 3px; - height: 30px; - width: 30px; - background-position: 5px 5px; - background-size: 20px; cursor: pointer; } @@ -3107,10 +3333,6 @@ See http://bgrins.github.io/spectrum/themes/ for instructions. bottom: 0; right: 0; border-bottom-left-radius: 3px; - background-image: url(../img/duplicate.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; cursor: pointer; } @@ -3118,10 +3340,6 @@ See http://bgrins.github.io/spectrum/themes/ for instructions. bottom: 0; left: 0; border-top-right-radius: 3px; - background-image: url(../img/dragndrop.png); - background-repeat: no-repeat; - background-position: 5px 5px; - background-size: 20px; cursor: move; } diff --git a/img/canvas-backgrounds/canvas-background-light.png b/img/canvas-backgrounds/canvas-background-light.png new file mode 100644 index 00000000..d11f6acd Binary files /dev/null and b/img/canvas-backgrounds/canvas-background-light.png differ diff --git a/img/canvas-backgrounds/canvas-background-lowcontrast-dark.png b/img/canvas-backgrounds/canvas-background-lowcontrast-dark.png new file mode 100644 index 00000000..9f8f188e Binary files /dev/null and b/img/canvas-backgrounds/canvas-background-lowcontrast-dark.png differ diff --git a/img/canvas-backgrounds/canvas-background-lowcontrast-medium.png b/img/canvas-backgrounds/canvas-background-lowcontrast-medium.png new file mode 100644 index 00000000..acd57cde Binary files /dev/null and b/img/canvas-backgrounds/canvas-background-lowcontrast-medium.png differ diff --git a/img/canvas-backgrounds/canvas-background-medium.png b/img/canvas-backgrounds/canvas-background-medium.png new file mode 100644 index 00000000..a90cd46c Binary files /dev/null and b/img/canvas-backgrounds/canvas-background-medium.png differ diff --git a/img/canvas_background/light_canvas_background.png b/img/canvas_background/light_canvas_background.png deleted file mode 100644 index 52b7242d..00000000 Binary files a/img/canvas_background/light_canvas_background.png and /dev/null differ diff --git a/img/canvas_background/lowcont_dark_canvas_background.png b/img/canvas_background/lowcont_dark_canvas_background.png deleted file mode 100644 index dc80a413..00000000 Binary files a/img/canvas_background/lowcont_dark_canvas_background.png and /dev/null differ diff --git a/img/canvas_background/lowcont_medium_canvas_background.png b/img/canvas_background/lowcont_medium_canvas_background.png deleted file mode 100644 index 3a21f204..00000000 Binary files a/img/canvas_background/lowcont_medium_canvas_background.png and /dev/null differ diff --git a/img/canvas_background/medium_canvas_background.png b/img/canvas_background/medium_canvas_background.png deleted file mode 100644 index 2b279524..00000000 Binary files a/img/canvas_background/medium_canvas_background.png and /dev/null differ diff --git a/img/cloud_export.png b/img/cloud_export.png deleted file mode 100644 index 654edc8c..00000000 Binary files a/img/cloud_export.png and /dev/null differ diff --git a/img/icons/circle.png b/img/cursors/circle.png similarity index 100% rename from img/icons/circle.png rename to img/cursors/circle.png diff --git a/img/icons/color-palette.png b/img/cursors/color-palette.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/color-palette.png rename to img/cursors/color-palette.png diff --git a/img/icons/dropper.png b/img/cursors/dropper.png similarity index 100% rename from img/icons/dropper.png rename to img/cursors/dropper.png diff --git a/img/icons/eraser.png b/img/cursors/eraser.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/eraser.png rename to img/cursors/eraser.png diff --git a/img/icons/hand.png b/img/cursors/hand.png similarity index 100% rename from img/icons/hand.png rename to img/cursors/hand.png diff --git a/img/icons/mirror-pen.png b/img/cursors/mirror-pen.png similarity index 100% rename from img/icons/mirror-pen.png rename to img/cursors/mirror-pen.png diff --git a/img/icons/paint-bucket.png b/img/cursors/paint-bucket.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/paint-bucket.png rename to img/cursors/paint-bucket.png diff --git a/img/icons/pen.png b/img/cursors/pen.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/pen.png rename to img/cursors/pen.png diff --git a/img/icons/rectangle.png b/img/cursors/rectangle.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/rectangle.png rename to img/cursors/rectangle.png diff --git a/img/icons/select.png b/img/cursors/select.png similarity index 100% rename from img/icons/select.png rename to img/cursors/select.png diff --git a/img/icons/stroke.png b/img/cursors/stroke.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/stroke.png rename to img/cursors/stroke.png diff --git a/img/icons/vertical-mirror-pen.png b/img/cursors/vertical-mirror-pen.png similarity index 100% rename from img/icons/vertical-mirror-pen.png rename to img/cursors/vertical-mirror-pen.png diff --git a/img/icons/wand.png b/img/cursors/wand.png old mode 100755 new mode 100644 similarity index 100% rename from img/icons/wand.png rename to img/cursors/wand.png diff --git a/img/dragndrop.png b/img/dragndrop.png deleted file mode 100644 index b1657dfb..00000000 Binary files a/img/dragndrop.png and /dev/null differ diff --git a/img/duplicate.png b/img/duplicate.png deleted file mode 100755 index 38b6955e..00000000 Binary files a/img/duplicate.png and /dev/null differ diff --git a/img/export.png b/img/export.png deleted file mode 100644 index ad5a291f..00000000 Binary files a/img/export.png and /dev/null differ diff --git a/img/garbage.png b/img/garbage.png deleted file mode 100644 index cc08dae2..00000000 Binary files a/img/garbage.png and /dev/null differ diff --git a/img/gear.png b/img/gear.png deleted file mode 100644 index c09e06fa..00000000 Binary files a/img/gear.png and /dev/null differ diff --git a/img/icons.png b/img/icons.png new file mode 100644 index 00000000..83638553 Binary files /dev/null and b/img/icons.png differ diff --git a/img/icons/common/common-keyboard-gold.png b/img/icons/common/common-keyboard-gold.png new file mode 100644 index 00000000..c765e6d6 Binary files /dev/null and b/img/icons/common/common-keyboard-gold.png differ diff --git a/img/icons/common/common-swapcolors-arrow-grey.png b/img/icons/common/common-swapcolors-arrow-grey.png new file mode 100644 index 00000000..d8b57c3f Binary files /dev/null and b/img/icons/common/common-swapcolors-arrow-grey.png differ diff --git a/img/icons/frame/frame-dragndrop-white.png b/img/icons/frame/frame-dragndrop-white.png new file mode 100644 index 00000000..22c620db Binary files /dev/null and b/img/icons/frame/frame-dragndrop-white.png differ diff --git a/img/icons/frame/frame-duplicate-white.png b/img/icons/frame/frame-duplicate-white.png new file mode 100644 index 00000000..0795aeb7 Binary files /dev/null and b/img/icons/frame/frame-duplicate-white.png differ diff --git a/img/icons/frame/frame-plus-white.png b/img/icons/frame/frame-plus-white.png new file mode 100644 index 00000000..2a4104ce Binary files /dev/null and b/img/icons/frame/frame-plus-white.png differ diff --git a/img/icons/frame/frame-recyclebin-white.png b/img/icons/frame/frame-recyclebin-white.png new file mode 100644 index 00000000..8554e55a Binary files /dev/null and b/img/icons/frame/frame-recyclebin-white.png differ diff --git a/img/icons/minimap/minimap-popup-preview-arrow-gold.png b/img/icons/minimap/minimap-popup-preview-arrow-gold.png new file mode 100644 index 00000000..c437ae00 Binary files /dev/null and b/img/icons/minimap/minimap-popup-preview-arrow-gold.png differ diff --git a/img/icons/minimap/minimap-popup-preview-arrow-white.png b/img/icons/minimap/minimap-popup-preview-arrow-white.png new file mode 100644 index 00000000..b97bd38b Binary files /dev/null and b/img/icons/minimap/minimap-popup-preview-arrow-white.png differ diff --git a/img/icons/settings/settings-export-white.png b/img/icons/settings/settings-export-white.png new file mode 100644 index 00000000..b869cd09 Binary files /dev/null and b/img/icons/settings/settings-export-white.png differ diff --git a/img/icons/settings/settings-gear-white.png b/img/icons/settings/settings-gear-white.png new file mode 100644 index 00000000..1c638b6f Binary files /dev/null and b/img/icons/settings/settings-gear-white.png differ diff --git a/img/icons/settings/settings-open-folder-white.png b/img/icons/settings/settings-open-folder-white.png new file mode 100644 index 00000000..3630df10 Binary files /dev/null and b/img/icons/settings/settings-open-folder-white.png differ diff --git a/img/icons/settings/settings-resize-white.png b/img/icons/settings/settings-resize-white.png new file mode 100644 index 00000000..f2f17eaf Binary files /dev/null and b/img/icons/settings/settings-resize-white.png differ diff --git a/img/icons/settings/settings-save-white.png b/img/icons/settings/settings-save-white.png new file mode 100644 index 00000000..d8dfeadd Binary files /dev/null and b/img/icons/settings/settings-save-white.png differ diff --git a/img/icons/tools/tool-circle.png b/img/icons/tools/tool-circle.png new file mode 100644 index 00000000..7f4dbd97 Binary files /dev/null and b/img/icons/tools/tool-circle.png differ diff --git a/img/icons/tools/tool-colorpicker.png b/img/icons/tools/tool-colorpicker.png new file mode 100644 index 00000000..fe4cbcb8 Binary files /dev/null and b/img/icons/tools/tool-colorpicker.png differ diff --git a/img/icons/tools/tool-colorswap.png b/img/icons/tools/tool-colorswap.png new file mode 100644 index 00000000..ac316bc2 Binary files /dev/null and b/img/icons/tools/tool-colorswap.png differ diff --git a/img/icons/tools/tool-dithering.png b/img/icons/tools/tool-dithering.png new file mode 100644 index 00000000..7290eb86 Binary files /dev/null and b/img/icons/tools/tool-dithering.png differ diff --git a/img/icons/tools/tool-eraser.png b/img/icons/tools/tool-eraser.png new file mode 100644 index 00000000..88fa7583 Binary files /dev/null and b/img/icons/tools/tool-eraser.png differ diff --git a/img/icons/tools/tool-lasso-select.png b/img/icons/tools/tool-lasso-select.png new file mode 100644 index 00000000..0e9abc14 Binary files /dev/null and b/img/icons/tools/tool-lasso-select.png differ diff --git a/img/icons/tools/tool-lighten.png b/img/icons/tools/tool-lighten.png new file mode 100644 index 00000000..4a3a993e Binary files /dev/null and b/img/icons/tools/tool-lighten.png differ diff --git a/img/icons/tools/tool-move.png b/img/icons/tools/tool-move.png new file mode 100644 index 00000000..7911e1a7 Binary files /dev/null and b/img/icons/tools/tool-move.png differ diff --git a/img/icons/tools/tool-paint-bucket.png b/img/icons/tools/tool-paint-bucket.png new file mode 100644 index 00000000..cea3ed36 Binary files /dev/null and b/img/icons/tools/tool-paint-bucket.png differ diff --git a/img/icons/tools/tool-pen.png b/img/icons/tools/tool-pen.png new file mode 100644 index 00000000..6f3a0317 Binary files /dev/null and b/img/icons/tools/tool-pen.png differ diff --git a/img/icons/tools/tool-rectangle-select.png b/img/icons/tools/tool-rectangle-select.png new file mode 100644 index 00000000..421e0f96 Binary files /dev/null and b/img/icons/tools/tool-rectangle-select.png differ diff --git a/img/icons/tools/tool-rectangle.png b/img/icons/tools/tool-rectangle.png new file mode 100644 index 00000000..3fa778d3 Binary files /dev/null and b/img/icons/tools/tool-rectangle.png differ diff --git a/img/icons/tools/tool-shape-select.png b/img/icons/tools/tool-shape-select.png new file mode 100644 index 00000000..10da42f1 Binary files /dev/null and b/img/icons/tools/tool-shape-select.png differ diff --git a/img/icons/tools/tool-stroke.png b/img/icons/tools/tool-stroke.png new file mode 100644 index 00000000..39b9bc14 Binary files /dev/null and b/img/icons/tools/tool-stroke.png differ diff --git a/img/icons/tools/tool-vertical-mirror-pen.png b/img/icons/tools/tool-vertical-mirror-pen.png new file mode 100644 index 00000000..f5ffc49c Binary files /dev/null and b/img/icons/tools/tool-vertical-mirror-pen.png differ diff --git a/img/icons/transform/tool-clone.png b/img/icons/transform/tool-clone.png new file mode 100644 index 00000000..0425befd Binary files /dev/null and b/img/icons/transform/tool-clone.png differ diff --git a/img/icons/transform/tool-flip.png b/img/icons/transform/tool-flip.png new file mode 100644 index 00000000..4df04b16 Binary files /dev/null and b/img/icons/transform/tool-flip.png differ diff --git a/img/icons/transform/tool-rotate.png b/img/icons/transform/tool-rotate.png new file mode 100644 index 00000000..986837a8 Binary files /dev/null and b/img/icons/transform/tool-rotate.png differ diff --git a/img/import-icon.png b/img/import-icon.png deleted file mode 100644 index ed310656..00000000 Binary files a/img/import-icon.png and /dev/null differ diff --git a/img/keyboard.png b/img/keyboard.png deleted file mode 100644 index 8bed1a3a..00000000 Binary files a/img/keyboard.png and /dev/null differ diff --git a/img/layers.svg b/img/layers.svg deleted file mode 100644 index 34f46180..00000000 --- a/img/layers.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - diff --git a/img/local-storage-icon.png b/img/local-storage-icon.png deleted file mode 100644 index d9b757e7..00000000 Binary files a/img/local-storage-icon.png and /dev/null differ diff --git a/img/merge-icon.png b/img/merge-icon.png deleted file mode 100644 index 3210c100..00000000 Binary files a/img/merge-icon.png and /dev/null differ diff --git a/img/plus.png b/img/plus.png deleted file mode 100644 index 6b60af79..00000000 Binary files a/img/plus.png and /dev/null differ diff --git a/img/popup-preview-arrow-gold.png b/img/popup-preview-arrow-gold.png deleted file mode 100644 index dcf38951..00000000 Binary files a/img/popup-preview-arrow-gold.png and /dev/null differ diff --git a/img/popup-preview-arrow-white.png b/img/popup-preview-arrow-white.png deleted file mode 100644 index 27b78b98..00000000 Binary files a/img/popup-preview-arrow-white.png and /dev/null differ diff --git a/img/resize-icon.png b/img/resize-icon.png deleted file mode 100644 index dcfb6520..00000000 Binary files a/img/resize-icon.png and /dev/null differ diff --git a/img/save.png b/img/save.png deleted file mode 100644 index fb044dc8..00000000 Binary files a/img/save.png and /dev/null differ diff --git a/img/tools/circle.png b/img/tools/circle.png deleted file mode 100644 index 5f88d096..00000000 Binary files a/img/tools/circle.png and /dev/null differ diff --git a/img/tools/clone.png b/img/tools/clone.png deleted file mode 100644 index ca02ff71..00000000 Binary files a/img/tools/clone.png and /dev/null differ diff --git a/img/tools/eraser.png b/img/tools/eraser.png deleted file mode 100644 index 2df7c84b..00000000 Binary files a/img/tools/eraser.png and /dev/null differ diff --git a/img/tools/eyedropper.png b/img/tools/eyedropper.png deleted file mode 100644 index 84a27d22..00000000 Binary files a/img/tools/eyedropper.png and /dev/null differ diff --git a/img/tools/flip.png b/img/tools/flip.png deleted file mode 100644 index c2fbc8c8..00000000 Binary files a/img/tools/flip.png and /dev/null differ diff --git a/img/tools/hand.png b/img/tools/hand.png deleted file mode 100644 index 38187685..00000000 Binary files a/img/tools/hand.png and /dev/null differ diff --git a/img/tools/lighten.png b/img/tools/lighten.png deleted file mode 100644 index 59e036fb..00000000 Binary files a/img/tools/lighten.png and /dev/null differ diff --git a/img/tools/magicwand.png b/img/tools/magicwand.png deleted file mode 100644 index a7dea845..00000000 Binary files a/img/tools/magicwand.png and /dev/null differ diff --git a/img/tools/mirror.png b/img/tools/mirror.png deleted file mode 100644 index 272a37c4..00000000 Binary files a/img/tools/mirror.png and /dev/null differ diff --git a/img/tools/paintbucket.png b/img/tools/paintbucket.png deleted file mode 100644 index 092eea7b..00000000 Binary files a/img/tools/paintbucket.png and /dev/null differ diff --git a/img/tools/pen.png b/img/tools/pen.png deleted file mode 100644 index d1e6d3a4..00000000 Binary files a/img/tools/pen.png and /dev/null differ diff --git a/img/tools/rectangle.png b/img/tools/rectangle.png deleted file mode 100644 index 2898f4f8..00000000 Binary files a/img/tools/rectangle.png and /dev/null differ diff --git a/img/tools/rectangle_selection.png b/img/tools/rectangle_selection.png deleted file mode 100644 index af8c635d..00000000 Binary files a/img/tools/rectangle_selection.png and /dev/null differ diff --git a/img/tools/rotate.png b/img/tools/rotate.png deleted file mode 100644 index cea4c5cb..00000000 Binary files a/img/tools/rotate.png and /dev/null differ diff --git a/img/tools/stroke.png b/img/tools/stroke.png deleted file mode 100644 index 80aad556..00000000 Binary files a/img/tools/stroke.png and /dev/null differ diff --git a/img/tools/swap-arrow-square-small-grey.png b/img/tools/swap-arrow-square-small-grey.png deleted file mode 100644 index ce91d240..00000000 Binary files a/img/tools/swap-arrow-square-small-grey.png and /dev/null differ diff --git a/img/tools/swap-colors.png b/img/tools/swap-colors.png deleted file mode 100644 index b0ab7aa7..00000000 Binary files a/img/tools/swap-colors.png and /dev/null differ diff --git a/img/tools/circle-dark.png b/img/unused/circle-dark.png similarity index 100% rename from img/tools/circle-dark.png rename to img/unused/circle-dark.png diff --git a/img/tools/eraser-dark.png b/img/unused/eraser-dark.png similarity index 100% rename from img/tools/eraser-dark.png rename to img/unused/eraser-dark.png diff --git a/img/tools/eyedropper-dark.png b/img/unused/eyedropper-dark.png similarity index 100% rename from img/tools/eyedropper-dark.png rename to img/unused/eyedropper-dark.png diff --git a/img/gallery.png b/img/unused/gallery.png similarity index 100% rename from img/gallery.png rename to img/unused/gallery.png diff --git a/img/tools/hand-dark.png b/img/unused/hand-dark.png similarity index 100% rename from img/tools/hand-dark.png rename to img/unused/hand-dark.png diff --git a/img/unused/lasso-dark.png b/img/unused/lasso-dark.png new file mode 100644 index 00000000..d1644cc4 Binary files /dev/null and b/img/unused/lasso-dark.png differ diff --git a/img/tools/magicwand-dark.png b/img/unused/magicwand-dark.png similarity index 100% rename from img/tools/magicwand-dark.png rename to img/unused/magicwand-dark.png diff --git a/img/tools/paintbucket-dark.png b/img/unused/paintbucket-dark.png similarity index 100% rename from img/tools/paintbucket-dark.png rename to img/unused/paintbucket-dark.png diff --git a/img/tools/pen-dark.png b/img/unused/pen-dark.png similarity index 100% rename from img/tools/pen-dark.png rename to img/unused/pen-dark.png diff --git a/img/tools/rectangle-dark.png b/img/unused/rectangle-dark.png similarity index 100% rename from img/tools/rectangle-dark.png rename to img/unused/rectangle-dark.png diff --git a/img/tools/rectangle_selection-dark.png b/img/unused/rectangle_selection-dark.png similarity index 100% rename from img/tools/rectangle_selection-dark.png rename to img/unused/rectangle_selection-dark.png diff --git a/index.html b/index.html index e7e2770e..a6413c59 100644 --- a/index.html +++ b/index.html @@ -22,17 +22,86 @@ color:white;"> Loading Piskel ... - + +
- +
+
+
+
+
+
+
+
+
+
    + +
+
+
+ +
+
+ +
+
+
+
+
+ + + + + +
- +
+
+
    +
    +
    +
    +
    @@ -42,24 +111,145 @@
    - - - - +
    +
    +
    +
    1x
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +

    Layers +
    +

    +
    + + + + + + + + + + + + +
    + +
      + + +
      + +
      +

      Transform

      +
        +
        +
        +

        Palettes

        +
        + + + +
        +
        + + + + +
        + + +
        - +
        +
        +
        + +
        +
        + +
        +
        + +
        +
        + +
        +
        + +
        - - - - -
        @@ -68,17 +258,726 @@
        - - -
        - - - +
        + - + + + + + + + + +
        +
        + +
        + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/lib/iframeLoader-0.1.0.js b/js/lib/iframeLoader-0.1.0.js deleted file mode 100644 index 645a7f6f..00000000 --- a/js/lib/iframeLoader-0.1.0.js +++ /dev/null @@ -1,52 +0,0 @@ -(function () { - /** - * Depending on the value of the data-iframe-loader attribute, display or store the content of the iframe - * @param {HTMLElement} iframe - */ - var processFrame = function (iframe) { - var type = iframe.getAttribute('data-iframe-loader'); - if (type === "display") { - displayFrame(iframe); - } else if (type === "store") { - storeFrame(iframe); - } else { - console.error('iframeLoader invalid type : ' + type); - } - }; - - /** - * Replace the existing iframe with the content of the iframe - * If the iframe has a single root element, it will directly replace the iframe. - * If there are several roots, a wrapping div will be created and will replace the iframe - * @param {HTMLElement} iframe - */ - var displayFrame = function (iframe) { - var div=document.createElement("div"); - div.innerHTML = iframe.contentWindow.document.body.innerHTML; - if (div.children.length == 1) { - div = div.children[0]; - } - iframe.parentNode.replaceChild(div, iframe); - }; - - /** - * Load the iframe content as a - * The content can later be accessed by getting the script (through getElementById for instance) and reading innerHTML - * @param {HTMLElement} iframe - */ - var storeFrame = function (iframe) { - var script=document.createElement("script"); - script.setAttribute("type", "text/html"); - script.setAttribute("id", iframe.getAttribute("src").replace(/.*templates[^\/]*\//,'templates/')); - script.innerHTML = iframe.contentWindow.document.body.innerHTML; - iframe.parentNode.removeChild(iframe); - document.body.appendChild(script); - }; - - window.iframeloader = { - onLoad : function (event) { - var iframe = event.target || event.srcElement; - processFrame(iframe); - } - }; -})(); \ No newline at end of file diff --git a/js/piskel-packaged-2014-07-14-04-44.js b/js/piskel-packaged-2014-07-14-04-44.js deleted file mode 100644 index 103ad170..00000000 --- a/js/piskel-packaged-2014-07-14-04-44.js +++ /dev/null @@ -1,22765 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - OVERLAY_ONION_SKIN : 'onion-skin', - OVERLAY_LAYER_PREVIEW : 'layer-preview', - OVERLAY_DISABLED : 'no-overlay', - - NO_PALETTE_ID : '__no-palette', - CURRENT_COLORS_PALETTE_ID : '__current-colors', - MANAGE_PALETTE_ID : '__manage-palettes', - - // Used for Spectrum input - PREFERRED_COLOR_FORMAT : 'rgb', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - /* - * Default entry point for piskel web service: - */ - STATIC : { - URL : { - SAVE : 'http://3.piskel-app.appspot.com/store', - GET : 'http://3.piskel-app.appspot.com/get' - } - }, - APPENGINE : { - URL : { - SAVE : 'save' - } - }, - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-a.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-a.appspot.com/img/', - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {} -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - TOOL_RELEASED : "TOOL_RELEASED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i 255 || g > 255 || b > 255) { - throw "Invalid color component"; - } - - return ((r << 16) | (g << 8) | b).toString(16); - }; - - ns.normalize = function (value, def) { - if (typeof value === 'undefined' || value === null) { - return def; - } else { - return value; - } - }; - - ns.inherit = function(extendedObject, inheritFrom) { - extendedObject.prototype = Object.create(inheritFrom.prototype); - extendedObject.prototype.constructor = extendedObject; - extendedObject.prototype.superclass = inheritFrom.prototype; - }; - - ns.wrap = function (wrapper, wrappedObject) { - for (var prop in wrappedObject) { - if (typeof wrappedObject[prop] === 'function' && typeof wrapper[prop] === 'undefined') { - wrapper[prop] = wrappedObject[prop].bind(wrappedObject); - } - } - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement("canvas"); - canvas.setAttribute("width", width); - canvas.setAttribute("height", height); - - if (typeof classList == "string") { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = false; - context.mozImageSmoothingEnabled = false; - context.oImageSmoothingEnabled = false; - context.webkitImageSmoothingEnabled = false; - context.msImageSmoothingEnabled = false; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || "png"; - var data = canvas.toDataURL("image/" + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (p, col, row) { - if (p != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, p); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData(imgData, w, h); - }, - - createFromImageData : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Convert a rgb(Number, Number, Number) color to hexadecimal representation - * @param {Number} r red value, between 0 and 255 - * @param {Number} g green value, between 0 and 255 - * @param {Number} b blue value, between 0 and 255 - * @return {String} hex representation of the color '#ABCDEF' - */ - rgbToHex : function (r, g, b) { - return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b); - }, - - /** - * Convert a color component (as a Number between 0 and 255) to its string hexa representation - * @param {Number} c component value, between 0 and 255 - * @return {String} eg. '0A' - */ - componentToHex : function (c) { - var hex = c.toString(16); - return hex.length == 1 ? "0" + hex : hex; - }, - - toImage : function (frame, zoom, bgColor) { - zoom = zoom || 1; - bgColor = bgColor || Constants.TRANSPARENT_COLOR; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(bgColor); - return canvasRenderer.render(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image, frameCount) { - var w = image.width, - h = image.height, - frameWidth = w / frameCount; - - var canvas = pskl.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - var imgData = context.getImageData(frameWidth*i,0,frameWidth,h).data; - var frame = pskl.utils.FrameUtils.createFromImageData(imgData, frameWidth, h); - frames.push(frame); - } - return frames; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = window.atob(content.replace(/data\:.*?\;base64\,/,'')); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(Constants.PREFERRED_COLOR_FORMAT || format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.previousStates = [this.getPixels()]; - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.length() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.length = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = JSON.stringify(frame.getPixels()); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].length() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.drawingtools.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classes array of strings to use for css classes - */ - ns.FrameRenderer = function (container, renderingOptions, classes) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classes = classes || []; - this.classes.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.CanvasUtils.clear(this.canvas); - pskl.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.CanvasUtils.createCanvas(width, height, this.classes); - pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - this.renderPixel_(color, x, y, context); - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["onion-skin-canvas"]); - - this.add(this.renderer); - - this.serializedRendering = ''; - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - - var frames = []; - this.addFrameAtIndexToArray_(currentFrameIndex - 1, frames); - this.addFrameAtIndexToArray_(currentFrameIndex + 1, frames); - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - if (frames.length > 0) { - this.clear(); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.addFrameAtIndexToArray_ = function (frameIndex, frames) { - var layer = this.piskelController.getCurrentLayer(); - if (this.piskelController.hasFrameAt(frameIndex)) { - frames.push(layer.getFrameAt(frameIndex)); - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - this.displayContainer = document.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classes array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classes) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classes); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - this.frame.forEachPixel(function (color, x, y) { - this.renderPixel_(color, x, y, context); - }.bind(this)); - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * animationController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.animationController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.length(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PublicPiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.addFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.addFrameAt, [index]); - this.piskelController.addFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.removeFrameAt, [index]); - this.piskelController.removeFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT, - scope : this, - replay : { - fn : fn, - args : args - } - }); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; - - ns.PublicPiskelController.prototype.duplicateFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt, [index]); - this.piskelController.duplicateFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.raiseSaveStateEvent_(this.piskelController.moveFrame, [fromIndex, toIndex]); - this.piskelController.moveFrame(fromIndex, toIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentFrameIndex = function (index) { - this.piskelController.setCurrentFrameIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectNextFrame = function () { - this.piskelController.selectNextFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectPreviousFrame = function () { - this.piskelController.selectPreviousFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentLayerIndex = function (index) { - this.piskelController.setCurrentLayerIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectLayer = function (layer) { - this.piskelController.selectLayer(layer); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.renameLayerAt = function (index, name) { - this.raiseSaveStateEvent_(this.piskelController.renameLayerAt, [index, name]); - this.piskelController.renameLayerAt(index, name); - }; - - ns.PublicPiskelController.prototype.createLayer = function (name) { - this.raiseSaveStateEvent_(this.piskelController.createLayer, [name]); - this.piskelController.createLayer(name); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerUp = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerUp, []); - this.piskelController.moveLayerUp(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerDown = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerDown, []); - this.piskelController.moveLayerDown(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.raiseSaveStateEvent_(this.piskelController.removeLayerAt, [currentLayerIndex]); - this.piskelController.removeLayerAt(currentLayerIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.getCurrentLayerIndex = function () { - return this.piskelController.getCurrentLayerIndex(); - }; - - ns.PublicPiskelController.prototype.getCurrentFrameIndex = function () { - return this.piskelController.currentFrameIndex; - }; - - ns.PublicPiskelController.prototype.getPiskel = function () { - return this.piskelController.piskel; - }; - -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - // TODO(vincz): Store user prefs in a localstorage string ? - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = new pskl.rendering.OnionSkinRenderer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChanged_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(this.afterWindowResize_.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChanged_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - var frame = this.piskelController.getCurrentFrame(); - var coords = this.renderer.getCoordinates(event.clientX, event.clientY); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.isClicked = true; - this.setCurrentButton(event); - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.renderer.getCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } else { - - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - var delta = event.wheelDeltaY || (-2 * event.deltaY); - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - if(this.isClicked) { - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - var coords = this.renderer.getCoordinates(event.clientX, event.clientY); - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.calculateZoom_() * this.piskelController.getCurrentFrame().getHeight(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.calculateZoom_() * this.piskelController.getCurrentFrame().getWidth(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.PreviewFilmController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.PreviewFilmController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.PreviewFilmController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.PreviewFilmController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.PreviewFilmController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.PreviewFilmController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.PreviewFilmController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.PreviewFilmController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.PreviewFilmController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.PreviewFilmController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.PreviewFilmController.prototype.calculateZoom_ = function () { - var curFrame = this.piskelController.getCurrentFrame(), - frameHeight = curFrame.getHeight(), - frameWidth = curFrame.getWidth(); - - return Math.min(Constants.PREVIEW_FILM_SIZE/frameHeight, Constants.PREVIEW_FILM_SIZE/frameWidth); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } else if (el.classList.contains('edit-icon')) { - index = el.parentNode.dataset.layerIndex; - this.renameLayerAt_(index); - } - }; - - ns.LayersListController.prototype.renameLayerAt_ = function (index) { - var layer = this.piskelController.getLayerAt(index); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.AnimatedPreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - }; - - ns.AnimatedPreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); - document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin"); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - }; - - ns.AnimatedPreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.AnimatedPreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.AnimatedPreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.AnimatedPreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.AnimatedPreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt($("#preview-fps")[0].value, 10)); - }; - - ns.AnimatedPreviewController.prototype.setFPS = function (fps) { - if (fps) { - this.fps = fps; - $("#preview-fps").val(this.fps); - $("#display-fps").html(this.fps + " FPS"); - } - }; - - ns.AnimatedPreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.AnimatedPreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (index != this.currentIndex) { - this.currentIndex = index; - if (!this.piskelController.hasFrameAt(this.currentIndex)) { - this.currentIndex = 0; - this.elapsedTime = 0; - } - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewSize = 200, - hZoom = previewSize / frame.getHeight(), - wZoom = previewSize / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.AnimatedPreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.AnimatedPreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + "px"; - containerEl.style.width = width + "px"; - containerEl.style.marginTop = ((PREVIEW_SIZE - height) / 2) + "px"; - containerEl.style.marginBottom = ((PREVIEW_SIZE - height) / 2) + "px"; - containerEl.style.marginLeft = ((PREVIEW_SIZE - width) / 2) + "px"; - containerEl.style.marginRight = ((PREVIEW_SIZE - width) / 2) + "px"; - }; - - ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, animationController, drawingController, container) { - this.piskelController = piskelController; - this.animationController = animationController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.cropFrame = document.createElement('DIV'); - this.cropFrame.className = 'minimap-crop-frame'; - this.cropFrame.style.display = 'none'; - $(this.container).append(this.cropFrame); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var zoomRatio = this.getDrawingAreaZoomRatio_(); - if (zoomRatio > 1) { - this.displayCropFrame_(zoomRatio, this.drawingController.getRenderer().getOffset()); - } else { - this.hideCropFrame_(); - } - }; - - ns.MinimapController.prototype.displayCropFrame_ = function (ratio, offset) { - this.cropFrame.style.display = 'block'; - this.cropFrame.style.top = (offset.y * this.animationController.getZoom()) + 'px'; - this.cropFrame.style.left = (offset.x * this.animationController.getZoom()) + 'px'; - var zoomRatio = this.getDrawingAreaZoomRatio_(); - this.cropFrame.style.width = (this.container.width() / zoomRatio) + 'px'; - this.cropFrame.style.height = (this.container.height() / zoomRatio) + 'px'; - - }; - - ns.MinimapController.prototype.hideCropFrame_ = function () { - this.cropFrame.style.display = 'none'; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isClicked) { - if (this.getDrawingAreaZoomRatio_() > 1) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.animationController.getCoordinates(x, y); - var zoomRatio = this.getDrawingAreaZoomRatio_(); - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / zoomRatio; - var height = frameHeight / zoomRatio; - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getDrawingAreaZoomRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var drawingAreaFullHeight = this.piskelController.getCurrentFrame().getHeight() * drawingAreaZoom; - var zoomRatio = drawingAreaFullHeight / this.drawingController.getRenderer().getDisplaySize().height; - - return zoomRatio; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.drawingtools.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.drawingtools.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.drawingtools.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.drawingtools.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.drawingtools.Eraser()), - toDescriptor('stroke', 'L', new pskl.drawingtools.Stroke()), - toDescriptor('rectangle', 'R', new pskl.drawingtools.Rectangle()), - toDescriptor('circle', 'C', new pskl.drawingtools.Circle()), - toDescriptor('move', 'M', new pskl.drawingtools.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.drawingtools.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.drawingtools.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.drawingtools.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.drawingtools.ColorPicker()) - ]; - - this.currentSelectedTool = this.tools[0]; - this.previousSelectedTool = this.tools[0]; - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.drawingtools.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.instance.toolId == toolId) { - return tool; - } - } - return null; - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var toolMarkup = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - toolMarkup += this.getToolMarkup_(this.tools[i]); - } - $('#tools-container').html(toolMarkup); - }; - - /** - * @private - */ - ns.ToolController.prototype.getToolMarkup_ = function(tool) { - var toolId = tool.instance.toolId; - - var classList = ['tool-icon', toolId]; - if (this.currentSelectedTool == tool) { - classList.push('selected'); - } - - var tpl = pskl.utils.Template.get('drawing-tool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : classList.join(' '), - toolid : toolId, - title : tool.instance.getTooltipText(tool.shortcut) - }); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - this.paletteListOptGroup_ = document.querySelector('.palettes-list-select-group'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - - this.fillPaletteList(); - this.selectPaletteFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = [{ - id : Constants.NO_PALETTE_ID, - name : 'No palette' - }]; - palettes = palettes.concat(this.retrievePalettes()); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.paletteListOptGroup_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - var colors = this.getSelectedPaletteColors_(); - - var html = colors.map(function (color) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var paletteId = this.colorPaletteSelect_.value; - if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { - colors = this.usedColorService.getCurrentColors(); - } else { - var palette = this.getPaletteById(paletteId, this.retrievePalettes()); - if (palette) { - colors = palette.colors; - } - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.selectPaletteFromUserSettings = function () { - this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE)); - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - if (paletteId === Constants.MANAGE_PALETTE_ID) { - $.publish(Events.DIALOG_DISPLAY, 'manage-palettes'); - this.selectPaletteFromUserSettings(); - } else { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - } - - this.fillColorListContainer(); - }; - - - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.selectPaletteFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PalettesListController.prototype.retrievePalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - $(message).find(".close").click($.proxy(this.removeMessage_, this)); - if(messageInfo.behavior) { - messageInfo.behavior(message); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - /** - * @public - */ - ns.ApplicationSettingsController.prototype.init = function() { - // Highlight selected background picker: - var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - $('#background-picker-wrapper') - .find('.background-picker[data-background-class=' + backgroundClass + ']') - .addClass('selected'); - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - $('#grid-width').val(gridWidth); - $('#grid-width').change(this.onGridWidthChange.bind(this)); - - // Handle canvas background changes: - $('#background-picker-wrapper').click(this.onBackgroundClick.bind(this)); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange = function (evt) { - var width = $('#grid-width').val(); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, parseInt(width, 10)); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick = function (evt) { - var target = $(evt.target).closest('.background-picker'); - if (target.length) { - var backgroundClass = target.data('background-class'); - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); - - $('.background-picker').removeClass('selected'); - target.addClass('selected'); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ResizeController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.ResizeController.prototype.init = function () { - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - - this.resizeWidth.val(this.piskelController.getWidth()); - this.resizeHeight.val(this.piskelController.getHeight()); - - this.cancelButton = $('.resize-cancel-button'); - this.cancelButton.click(this.onCancelButtonClicked_.bind(this)); - - this.resizeForm = $("[name=resize-form]"); - this.resizeForm.submit(this.onResizeFormSubmit_.bind(this)); - - this.resizeContentCheckbox = $(".resize-content-checkbox"); - }; - - ns.ResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - - var width = parseInt(this.resizeWidth.val(), 10); - var height = parseInt(this.resizeHeight.val(), 10); - - var resizeContentEnabled = this.isResizeContentEnabled_(); - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - ns.ResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.ResizeController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.resizeWidth.val(), 10); - var height = parseInt(this.resizeHeight.val(), 10); - - var resizedFrame; - if (this.isResizeContentEnabled_()) { - resizedFrame = pskl.utils.FrameUtils.resize(frame, width, height, false); - } else { - resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - if (x < resizedFrame.getWidth() && y < resizedFrame.getHeight()) { - resizedFrame.setPixel(x, y, color); - } - }); - } - - return resizedFrame; - }; - - ns.ResizeController.prototype.isResizeContentEnabled_ = function () { - return !!this.resizeContentCheckbox.prop('checked'); - }; - - ns.ResizeController.prototype.onCancelButtonClicked_ = function (evt) { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = $(".gif-upload-button"); - this.uploadButton.click(this.onUploadButtonClick_.bind(this)); - - this.downloadButton = $(".gif-download-button"); - this.downloadButton.click(this.onDownloadButtonClick_.bind(this)); - - this.exportProgressStatusEl = document.querySelector('.gif-export-progress-status'); - this.exportProgressBarEl = document.querySelector('.gif-export-progress-bar'); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.originalEvent.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.onGifRenderingCompleted_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, function (imageData) { - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }.bind(this)); - }; - - ns.GifExportController.prototype.onGifRenderingCompleted_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 2, - quality: 1, - width: this.piskelController.getWidth()*zoom, - height: this.piskelController.getHeight()*zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - gif.on('progress', function(percentage) { - this.updateProgressStatus_((percentage*100).toFixed(2)); - }.bind(this)); - - gif.on('finished', function(blob) { - this.hideProgressStatus_(); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - ns.GifExportController.prototype.updateProgressStatus_ = function (percentage) { - this.exportProgressStatusEl.innerHTML = percentage + '%'; - this.exportProgressBarEl.style.width = percentage + "%"; - - }; - - ns.GifExportController.prototype.hideProgressStatus_ = function () { - this.exportProgressStatusEl.innerHTML = ''; - this.exportProgressBarEl.style.width = "0"; - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelectorAll(".png-export-preview")[0]; - - document.querySelector(".png-download-button").addEventListener('click', this.onPngDownloadButtonClick_.bind(this)); - - document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this)); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var filename = "sprite_" + (i+1) + ".png"; - zip.file(filename, pskl.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - - // Only available in app-engine mode ... - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = $('#save-online-status'); - - this.saveFileStatus = $('#save-file-status'); - this.timestamp = new Date(); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = $('#save-description'); - this.descriptionInput.val(descriptor.description); - - this.isPublicCheckbox = $('input[name=save-public-checkbox]'); - this.isPublicCheckbox.prop('checked', descriptor.isPublic); - - this.saveFileButton = $('#save-file-button'); - this.saveFileButton.click(this.saveFile_.bind(this)); - - this.saveLocalButton = $('#save-browser-button'); - this.saveLocalButton.click(this.saveLocal_.bind(this)); - - this.saveOnlineButton = $('#save-online-button'); - this.saveOnlineButton.click(this.saveOnline_.bind(this)); - - this.saveForm = $('form[name=save-form]'); - this.saveForm.submit(this.onSaveFormSubmit_.bind(this)); - - this.nameInput = $('#save-name'); - this.nameInput.val(descriptor.name); - this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this)); - - if (!pskl.app.isLoggedIn()) { - this.saveOnlineButton.hide(); - $('.save-public-section').hide(); - this.saveOnlineStatus.html(pskl.utils.Template.get('save-please-login-partial')); - this.saveFileButton.get(0).classList.add('button-primary'); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.html(pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - })); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.html('Saving ...'); - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.val(); - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.val(); - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.html(''); - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - this.importedImage_ = null; - }; - - ns.ImportController.prototype.init = function () { - this.browseLocalButton = document.querySelector('.browse-local-button'); - this.browseLocalButton.addEventListener('click', this.onBrowseLocalClick_.bind(this)); - - this.hiddenFileInput = $('[name=file-upload-input]'); - this.hiddenFileInput.change(this.onFileUploadChange_.bind(this)); - - this.fileInputButton = $('.file-input-button'); - this.fileInputButton.click(this.onFileInputClick_.bind(this)); - - this.hiddenOpenPiskelInput = $('[name=open-piskel-input]'); - this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this)); - - this.openPiskelInputButton = $('.open-piskel-button'); - this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this)); - - this.prevSessionContainer = $('.previous-session'); - this.previousSessionTemplate_ = pskl.utils.Template.get("previous-session-info-template"); - this.fillRestoreSession_(); - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - this.openPiskelFile_(); - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function () { - var files = this.hiddenOpenPiskelInput.get(0).files; - if (files.length == 1) { - - var file = files[0]; - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - this.closeDrawer_(); - } - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.get(0).files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.fillRestoreSession_ = function () { - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var info = { - name : previousInfo.name, - date : pskl.utils.DateUtils.format(previousInfo.date, "{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}") - }; - - this.prevSessionContainer.html(pskl.utils.Template.replace(this.previousSessionTemplate_, info)); - $(".restore-session-button").click(this.onRestorePreviousSessionClick_.bind(this)); - } else { - this.prevSessionContainer.html("No piskel backup was found on this browser."); - } - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - (new settings[setting].controller(this.piskelController)).init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - this.currentSetting = setting; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - $.publish(Events.DIALOG_HIDE); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var tinycolor = window.tinycolor; - - var SELECTED_CLASSNAME = 'selected'; - var NEW_COLOR_CLASS = 'palette-manager-new-color'; - var CLOSE_ICON_CLASS = 'palette-manager-delete-card'; - var EDIT_NAME_CLASS = 'edit-icon'; - - ns.PaletteManagerController = function (piskelController) { - this.piskelController = piskelController; - this.palettes = this.retrieveUserPalettes(); - this.originalPalettes = this.retrieveUserPalettes(); - this.selectedPaletteId = null; - - // Keep track of all spectrum instances created, to dispose them when closing the popup - this.spectrumContainers = []; - }; - - pskl.utils.inherit(ns.PaletteManagerController, ns.AbstractDialogController); - - ns.PaletteManagerController.prototype.init = function () { - this.superclass.init.call(this); - - this.palettesList = document.querySelector('.palette-manager-list'); - this.paletteBody = document.querySelector('.palette-manager-details-body'); - this.paletteHead = document.querySelector('.palette-manager-details-head'); - this.createButton = document.querySelector('.palette-manager-actions-button[data-action="create"]'); - this.saveAllButton = document.querySelector('.palette-manager-actions-button[data-action="save-all"]'); - - this.colorCardTemplate = pskl.utils.Template.get('palette-color-card-template'); - this.newColorTemplate = pskl.utils.Template.get('palette-new-color-template'); - this.paletteHeadTemplate = pskl.utils.Template.get('palette-details-head-template'); - - // Events - this.palettesList.addEventListener('click', this.onPaletteListClick.bind(this)); - // Delegated event listener for events repeated on all cards - this.paletteBody.addEventListener('click', this.delegatedPaletteBodyClick.bind(this)); - this.paletteHead.addEventListener('click', this.delegatedPaletteHeadClick.bind(this)); - this.createButton.addEventListener('click', this.onCreateClick_.bind(this)); - this.saveAllButton.addEventListener('click', this.saveAll.bind(this)); - - // Init markup - this.createPaletteListMarkup(); - if (this.palettes.length > 0) { - this.selectPalette(this.palettes[0].id); - } else { - this.createPalette('New palette'); - } - }; - - ns.PaletteManagerController.prototype.destroy = function () { - this.destroySpectrumPickers(); - }; - - ns.PaletteManagerController.prototype.onCreateClick_ = function (evt) { - this.createPalette(); - }; - - ns.PaletteManagerController.prototype.createPalette = function (name) { - if (!name) { - name = window.prompt('Please enter a name for your palette', 'New palette'); - } - if (name) { - var palette = this.createPaletteObject(name); - this.palettes.push(palette); - this.createPaletteListMarkup(); - this.selectPalette(palette.id); - } - }; - - ns.PaletteManagerController.prototype.createPaletteObject = function (name) { - return { - id : 'palette-' + Date.now() + '-' + Math.floor(Math.random()*1000), - name : name, - colors : [] - }; - }; - - ns.PaletteManagerController.prototype.redraw = function () { - this.createPaletteListMarkup(); - this.selectPalette(this.selectedPaletteId); - }; - - ns.PaletteManagerController.prototype.selectPalette = function (paletteId) { - this.deselectCurrentPalette(); - var paletteListItem = this.palettesList.querySelector('[data-palette-id='+paletteId+']'); - if (paletteListItem) { - this.selectedPaletteId = paletteId; - paletteListItem.classList.add(SELECTED_CLASSNAME); - this.refreshPaletteDetails(); - } - }; - - ns.PaletteManagerController.prototype.refreshPaletteDetails = function () { - this.createPaletteHeadMarkup(); - this.createPaletteBodyMarkup(); - this.initPaletteDetailsEvents(); - this.initPaletteCardsSpectrum(); - }; - - ns.PaletteManagerController.prototype.createPaletteListMarkup = function () { - var html = this.palettes.map(function (palette) { - var paletteCopy = { - id : palette.id, - name : this.isPaletteModified(palette) ? palette.name + " *" : palette.name - }; - return pskl.utils.Template.replace('
      • {{name}}
      • ', paletteCopy); - }.bind(this)).join(''); - this.palettesList.innerHTML = html; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteHeadMarkup = function () { - var palette = this.getSelectedPalette(); - var dict = { - 'name' : palette.name, - 'save:disabled' : !this.isPaletteModified(palette), - 'revert:disabled' : !this.isPaletteModified(palette), - 'delete:disabled' : this.palettes.length < 2 - }; - var html = pskl.utils.Template.replace(this.paletteHeadTemplate, dict); - - this.paletteHead.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.isPaletteModified = function (palette) { - var isModified = false; - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - if (originalPalette) { - var differentName = originalPalette.name !== palette.name; - var differentColors = palette.colors.join('') !== originalPalette.colors.join(''); - isModified = differentName || differentColors; - } else { - isModified = true; - } - return isModified; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteBodyMarkup = function () { - var palette = this.getSelectedPalette(); - - var html = this.getColorCardsMarkup(palette.colors); - html += pskl.utils.Template.replace(this.newColorTemplate, {classname : NEW_COLOR_CLASS}); - - this.paletteBody.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.initPaletteDetailsEvents = function () { - // New Card click event - var newCard = this.paletteBody.querySelector('.' + NEW_COLOR_CLASS); - newCard.addEventListener('click', this.onNewCardClick.bind(this)); - - if (this.palettes.length < 2) { - var deleteButton = this.paletteHead.querySelector('.palette-manager-palette-button[data-action="delete"]'); - deleteButton.setAttribute("disabled", "disabled"); - } - }; - - ns.PaletteManagerController.prototype.onNewCardClick = function () { - var color; - var palette = this.getSelectedPalette(); - if (palette && palette.colors.length > 0) { - color = palette.colors[palette.colors.length-1]; - } else { - color = '#FFFFFF'; - } - this.addColorInSelectedPalette(color); - }; - - ns.PaletteManagerController.prototype.delegatedPaletteBodyClick = function (event) { - var target = event.target; - if (target.classList.contains(CLOSE_ICON_CLASS)) { - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - this.removeColorInSelectedPalette(colorId); - } - }; - - ns.PaletteManagerController.prototype.delegatedPaletteHeadClick = function (event) { - var target = event.target; - if (target.classList.contains(EDIT_NAME_CLASS)) { - this.renameSelectedPalette(); - } else if (target.classList.contains('palette-manager-palette-button')) { - var action = target.dataset.action; - if (action === 'save') { - this.savePalette(this.getSelectedPalette().id); - this.redraw(); - } else if (action === 'revert') { - this.revertChanges(); - } else if (action === 'delete') { - this.deleteSelectedPalette(); - } - } - }; - - ns.PaletteManagerController.prototype.getSpectrumSelector_ = function () { - return ':not(.' + NEW_COLOR_CLASS + ')>.palette-manager-color-square'; - }; - - ns.PaletteManagerController.prototype.initPaletteCardsSpectrum = function () { - var oSelf = this; - var container = $(this.getSpectrumSelector_()); - container.spectrum({ - clickoutFiresChange : true, - showInput: true, - showButtons: false, - change : function (color) { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - oSelf.updateColorInSelectedPalette(colorId, color); - }, - beforeShow : function() { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - var palette = oSelf.getSelectedPalette(); - var color = palette.colors[colorId]; - container.spectrum("set", color); - } - }); - - this.spectrumContainers.push(container); - }; - - /** - * Destroy all spectrum instances generated by the palette manager - */ - ns.PaletteManagerController.prototype.destroySpectrumPickers = function () { - this.spectrumContainers.forEach(function (container) { - container.spectrum("destroy"); - }); - this.spectrumContainers = []; - }; - - ns.PaletteManagerController.prototype.updateColorInSelectedPalette = function (colorId, color) { - var palette = this.getSelectedPalette(); - var hexColor = '#' + (color.toHex().toUpperCase()); - palette.colors.splice(colorId, 1, hexColor); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.addColorInSelectedPalette = function (color) { - var selectedPalette = this.getSelectedPalette(); - selectedPalette.colors.push(color); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.removeColorInSelectedPalette = function (colorId) { - var palette = this.getSelectedPalette(); - palette.colors.splice(colorId, 1); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.renameSelectedPalette = function () { - var palette = this.getSelectedPalette(); - var name = window.prompt('Please enter a new name for palette "' + palette.name + '"', palette.name); - if (name) { - palette.name = name; - this.redraw(); - } - }; - - ns.PaletteManagerController.prototype.getSelectedPalette = function () { - return this.getPaletteById(this.selectedPaletteId, this.palettes); - }; - - ns.PaletteManagerController.prototype.getColorCardsMarkup = function (colors) { - var html = colors.map(function (color, index) { - var dict = { - colorId : index, - hex : color, - rgb : tinycolor(color).toRgbString(), - hsl : tinycolor(color).toHslString() - }; - return pskl.utils.Template.replace(this.colorCardTemplate, dict); - }.bind(this)).join(''); - return html; - }; - - ns.PaletteManagerController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PaletteManagerController.prototype.removePaletteById = function (paletteId, palettes) { - var palette = this.getPaletteById(paletteId, palettes); - if (palette) { - var index = palettes.indexOf(palette); - palettes.splice(index, 1); - } - }; - - ns.PaletteManagerController.prototype.deselectCurrentPalette = function () { - var selectedItem = this.palettesList.querySelector('.' + SELECTED_CLASSNAME); - if (selectedItem) { - this.selectedPaletteId = null; - selectedItem.classList.remove(SELECTED_CLASSNAME); - } - }; - - ns.PaletteManagerController.prototype.revertChanges = function () { - var palette = this.getSelectedPalette(); - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - palette.name = originalPalette.name; - palette.colors = originalPalette.colors.slice(0); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.deleteSelectedPalette = function () { - var palette = this.getSelectedPalette(); - if (this.palettes.length > 1) { - if (window.confirm('Are you sure you want to delete "' + palette.name + '" ?')) { - this.removePaletteById(palette.id, this.palettes); - this.removePaletteById(palette.id, this.originalPalettes); - - this.persistToLocalStorage(); - - this.createPaletteListMarkup(); - this.selectPalette(this.palettes[0].id); - } - } - }; - - ns.PaletteManagerController.prototype.onPaletteListClick = function (event) { - var target = event.target; - if (target.dataset.paletteId) { - this.selectPalette(target.dataset.paletteId); - } - }; - - ns.PaletteManagerController.prototype.saveAll = function () { - this.palettes.forEach(function (palette) { - this.savePalette(palette.id); - }.bind(this)); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.savePalette = function (paletteId) { - var palette = this.getPaletteById(paletteId, this.palettes); - var originalPalette = this.getPaletteById(paletteId, this.originalPalettes); - if (originalPalette) { - originalPalette.name = palette.name; - originalPalette.colors = palette.colors; - } else { - this.originalPalettes.push(palette); - } - - this.persistToLocalStorage(); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteManagerController.prototype.persistToLocalStorage = function () { - window.localStorage.setItem('piskel.palettes', JSON.stringify(this.originalPalettes)); - this.originalPalettes = this.retrieveUserPalettes(); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteManagerController.prototype.retrieveUserPalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readFile(this.file_, this.processImageSource_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - /** - * Create an image from the given source (url or data-url), and onload forward to onImageLoaded - * TODO : should be a generic utility method, should take a callback - * @param {String} imageSource url or data-url, will be used as src for the image - */ - ns.ImportImageController.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (evt) { - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'manage-palettes' : { - template : 'templates/dialogs/manage-palettes.html', - controller : ns.PaletteManagerController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'manage-palettes')); - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - this.dialogContainer_.classList.add(dialogId); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var formData = this.prepareFormData_(); - - var xhr = new XMLHttpRequest(); - xhr.open('POST', Constants.APPENGINE.URL.SAVE, true); - - xhr.onload = function(e) { - if (this.status == 200) { - callbacks.success(); - callbacks.after(); - } else { - this.onerror(e); - } - }; - xhr.onerror = function(e) { - callbacks.error(this.status); - callbacks.after(); - }; - xhr.send(formData); - }; - - ns.AppEngineStorageService.prototype.prepareFormData_ = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var formData = new FormData(); - formData.append('framesheet', this.piskelController.serialize()); - formData.append('fps', this.piskelController.getFPS()); - formData.append('name', descriptor.name); - formData.append('description', descriptor.description); - if (descriptor.isPublic) { - formData.append('public', true); - } - formData.append('frames', this.piskelController.getFrameCount()); - formData.append('first_frame_as_png', pskl.app.getFirstFrameAsPng()); - formData.append('framesheet_as_png', pskl.app.getFramesheetAsPng()); - - return formData; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - window.localStorage.setItem('bkp.prev.piskel', previousPiskel); - window.localStorage.setItem('bkp.prev.info', previousInfo); - } - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - window.localStorage.setItem('bkp.next.piskel', this.piskelController.serialize()); - window.localStorage.setItem('bkp.next.info', JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(previousInfo.fps); - }); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - var SNAPSHOT_PERIOD = 50; - var LOAD_STATE_INTERVAL = 50; - - ns.HistoryService = function (piskelController) { - this.piskelController = piskelController; - this.stateQueue = []; - this.currentIndex = -1; - this.saveState__b = this.onSaveStateEvent.bind(this); - - this.lastLoadState = -1; - - this.saveNextAsSnapshot = false; - }; - - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - ns.HistoryService.REPLAY = 'REPLAY'; - /** - * This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command. - * Don't store snapshots for such events. - */ - ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT'; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.saveState__b); - - pskl.app.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, stateInfo) { - this.saveState(stateInfo); - }; - - ns.HistoryService.prototype.saveState = function (stateInfo) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : stateInfo, - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT; - var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot; - if (isNoSnapshot && isAtAutoSnapshotInterval) { - this.saveNextAsSnapshot = true; - } else if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - this.saveNextAsSnapshot = false; - } - - if (isSnapshot) { - - } - - this.stateQueue.push(state); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcut('shift+?', this.toggleCheatsheet_.bind(this)); - pskl.app.shortcutService.addShortcut('?', this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Open the Palette Manager'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} cbSuccess success callback. 1st argument will be the uploaded image URL - * @param {Function} cbError error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, cbSuccess, cbError) { - var xhr = new XMLHttpRequest(); - var formData = new FormData(); - formData.append('data', imageData); - xhr.open('POST', Constants.IMAGE_SERVICE_UPLOAD_URL, true); - xhr.onload = function (e) { - if (this.status == 200) { - var imageUrl = Constants.IMAGE_SERVICE_GET_URL + this.responseText; - cbSuccess(imageUrl); - } else { - cbError(); - } - }; - - xhr.send(formData); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - this.currentColors = []; - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToColors_.bind(this)); - - this.framesColorsCache_ = {}; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); - $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.frameToColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - frameColors[color] = (frameColors[color] || 0) + 1; - }); - return frameColors; - }; - - - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = (colors[color] || 0) + frameColors[color]; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - this.currentColors = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - - // sort by most frequent color - this.currentColors = this.currentColors.sort(function (c1, c2) { - return colors[c2] - colors[c1]; - }); - - // TODO : only fire if there was a change - $.publish(Events.CURRENT_COLORS_UPDATED, colors); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - if (isImage) { - this.readImageFile_(file); - } else if (/\.piskel$/i.test(file.name)) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } - } - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;/** - * @provide pskl.drawingtools.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.drawingtools"); - - ns.BaseTool = function() { - this.toolId = "tool-base"; - }; - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.getHelpText = function() { - return this.shortHelpText || this.helpText; - }; - - ns.BaseTool.prototype.getTooltipText = function(shortcut) { - var tpl = pskl.utils.Template.get('drawing-tool-tooltip-container-template'); - - var descriptors = ""; - if (Array.isArray(this.tooltipDescriptors)) { - this.tooltipDescriptors.forEach(function (descriptor) { - descriptors += this.getTooltipDescription(descriptor); - }.bind(this)); - } - - return pskl.utils.Template.replace(tpl, { - helptext : this.getHelpText(), - shortcut : shortcut, - descriptors : descriptors - }); - }; - - ns.BaseTool.prototype.getTooltipDescription = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-simple-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.drawingtools'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [col, row]); - this.raiseSaveStateEvent({ - col : col, - row : row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.drawingtools.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.drawingtools"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing', - - // SERVICE URLS - APPENGINE_SAVE_URL : 'save', - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - SELECT_TOOL : "SELECT_TOOL", - - TOOL_RELEASED : "TOOL_RELEASED", - TOOL_PRESSED : "TOOL_PRESSED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - SHOW_PROGRESS: "SHOW_PROGRESS", - UPDATE_PROGRESS: "UPDATE_PROGRESS", - HIDE_PROGRESS: "HIDE_PROGRESS", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", - - MOUSE_EVENT : "MOUSE_EVENT", - - // Tests - TEST_RECORD_END : "TEST_RECORD_END", - TEST_CASE_END : "TEST_CASE_END", - TEST_SUITE_END : "TEST_SUITE_END" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i": ">", - '"': '"', - "'": ''', - "/": '/' - }; - ns.escapeHtml= function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml= function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], "g"); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Array = { - find : function (array, filterFn) { - var match = null; - array = Array.isArray(array) ? array : []; - var filtered = array.filter(filterFn); - if (filtered.length) { - match = filtered[0]; - } - return match; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/,'')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement('canvas'); - canvas.setAttribute('width', width); - canvas.setAttribute('height', height); - - if (typeof classList == 'string') { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.utils.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.utils.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = false; - context.mozImageSmoothingEnabled = false; - context.oImageSmoothingEnabled = false; - context.webkitImageSmoothingEnabled = false; - context.msImageSmoothingEnabled = false; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.utils.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || 'png'; - var data = canvas.toDataURL('image/' + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.FrameTransform = { - VERTICAL : 'vertical', - HORIZONTAL : 'HORIZONTAL', - flip : function (frame, axis) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - clone.forEachPixel(function (color, x, y) { - if (axis === ns.FrameTransform.VERTICAL) { - x = w-x-1; - } else if (axis === ns.FrameTransform.HORIZONTAL) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - return frame; - }, - - CLOCKWISE : 'clockwise', - COUNTERCLOCKWISE : 'counterclockwise', - rotate : function (frame, direction) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - var max = Math.max(w, h); - var xDelta = Math.ceil((max - w)/2); - var yDelta = Math.ceil((max - h)/2); - - frame.forEachPixel(function (color, x, y) { - var _x = x, _y = y; - - // Convert to square coords - x = x + xDelta; - y = y + yDelta; - - // Perform the rotation - var tmpX = x, tmpY = y; - if (direction === ns.FrameTransform.CLOCKWISE) { - x = tmpY; - y = max - 1 - tmpX; - } else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) { - y = tmpX; - x = max - 1 - tmpY; - } - - // Convert the coordinates back to the rectangular grid - x = x - xDelta; - y = y - yDelta; - if (clone.containsPixel(x, y)) { - frame.pixels[_x][_y] = clone.getPixel(x, y); - } else { - frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR; - } - }); - frame.version++; - return frame; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - /** - * Render a Frame object as an image. - * Can optionally scale it (zoom) - * @param {Frame} frame - * @param {Number} zoom - * @return {Image} - */ - toImage : function (frame, zoom) { - zoom = zoom || 1; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }, - - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (color, col, row) { - if (color != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, color); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.utils.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); - }, - - createFromImageData_ : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels__ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba__ : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createLayerFromSpritesheet : function (image, frameCount) { - var width = image.width, - height = image.height, - frameWidth = width / frameCount; - - var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, height); - var context = canvas.getContext('2d'); - - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - context.clearRect(0, 0 , frameWidth, height); - context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); - var frame = pskl.utils.FrameUtils.createFromImage(canvas); - frames.push(frame); - } - return frames; - }, - - mergeLayers : function (layerA, layerB) { - var framesA = layerA.getFrames(); - var framesB = layerB.getFrames(); - var mergedFrames = []; - framesA.forEach(function (frame, index) { - var otherFrame = framesB[index]; - mergedFrames.push(pskl.utils.FrameUtils.merge([otherFrame, frame])); - }); - var mergedLayer = pskl.model.Layer.fromFrames(layerA.getName(), mergedFrames); - return mergedLayer; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.utils.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.utils.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.utils.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.utils.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.TooltipFormatter = {}; - - - ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) { - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : helpText, - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function(){ - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var workers = {}; - - ns.WorkerUtils = { - createWorker : function (worker, workerId) { - if (!workers[workerId]) { - var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")]; - var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here - workers[workerId] = window.URL.createObjectURL(blob); - } - - return new Worker(workers[workerId]); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function (){}; - error = error || function (){}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function(e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function(e) { - error(e, this); - }; - - return xhr; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var step_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - step_callback = callback.step; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - if (!flat) { - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - } - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.size() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.size = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels())); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Palette = function (id, name, colors) { - this.id = id; - this.name = name; - this.colors = colors; - }; - - ns.Palette.fromObject = function (paletteObj) { - var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); - return new ns.Palette(paletteObj.id, paletteObj.name, colors); - }; - - ns.Palette.prototype.getColors = function () { - return this.colors; - }; - - ns.Palette.prototype.setColors = function (colors) { - this.colors = colors; - }; - - ns.Palette.prototype.get = function (index) { - return this.colors[index]; - }; - - ns.Palette.prototype.set = function (index, color) { - this.colors[index] = color; - }; - - ns.Palette.prototype.add = function (color) { - this.colors.push(color); - }; - - ns.Palette.prototype.size = function () { - return this.colors.length; - }; - - ns.Palette.prototype.removeAt = function (index) { - this.colors.splice(index, 1); - }; - - ns.Palette.prototype.move = function (oldIndex, newIndex) { - this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].size() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.addLayerAt = function (layer, index) { - this.layers.splice(index, 0, layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classList - */ - ns.FrameRenderer = function (container, renderingOptions, classList) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classList = classList || []; - this.classList.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.utils.CanvasUtils.clear(this.canvas); - pskl.utils.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.utils.CanvasUtils.createCanvas(width, height, this.classList); - pskl.utils.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) { - var cellSize = this.zoom; - - x = x * cellSize; - y = y * cellSize; - - x = x - this.offset.x * cellSize; - y = y - this.offset.y * cellSize; - - x = x + this.margin.x; - y = y + this.margin.y; - - var containerOffset = this.container.offset(); - x = x + containerOffset.left; - y = y + containerOffset.top; - - return { - x : x + (cellSize/2), - y : y + (cellSize/2) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - var w = 1; - while (color === frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width || this.canvas.height*this.zoom < this.displayCanvas.height) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, width); - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (renderer, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - this.renderer = renderer; - this.add(this.renderer); - - this.hash = ''; - }; - - ns.OnionSkinRenderer.createInContainer = function (container, renderingOptions, piskelController) { - // Do not use CachedFrameRenderers here, caching is performed in the render method - var renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ['onion-skin-canvas']); - return new ns.OnionSkinRenderer(renderer, piskelController); - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var frames = this.getOnionFrames_(); - var hash = this.computeHash_(frames); - if (this.hash != hash) { - this.hash = hash; - this.clear(); - if (frames.length > 0) { - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.getOnionFrames_ = function () { - var frames = []; - - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var layer = this.piskelController.getCurrentLayer(); - - var previousIndex = currentFrameIndex - 1; - var previousFrame = layer.getFrameAt(previousIndex); - if (previousFrame) { - frames.push(previousFrame); - } - - var nextIndex = currentFrameIndex + 1; - var nextFrame = layer.getFrameAt(nextIndex); - if (nextFrame) { - frames.push(nextFrame); - } - - return frames; - }; - - ns.OnionSkinRenderer.prototype.computeHash_ = function (frames) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - return [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join('-'); - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.hash = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - this.displayContainer = document.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classList) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classList); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - - for(var x = 0, width = this.frame.getWidth(); x < width; x++) { - for(var y = 0, height = this.frame.getHeight(); y < height; y++) { - var color = this.frame.getPixel(x, y); - var w = 1; - while (color === this.frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.utils.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, width); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * animationController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.animationController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.size(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.mergeDownLayerAt = function (index) { - var layer = this.getLayerByIndex(index); - var downLayer = this.getLayerByIndex(index-1); - if (layer && downLayer) { - var mergedLayer = pskl.utils.LayerUtils.mergeLayers(layer, downLayer); - this.removeLayerAt(index); - this.piskel.addLayerAt(mergedLayer, index); - this.removeLayerAt(index-1); - this.selectLayer(mergedLayer); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PublicPiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.addFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.addFrameAt, [index]); - this.piskelController.addFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.removeFrameAt, [index]); - this.piskelController.removeFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; - - ns.PublicPiskelController.prototype.duplicateFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt, [index]); - this.piskelController.duplicateFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.raiseSaveStateEvent_(this.piskelController.moveFrame, [fromIndex, toIndex]); - this.piskelController.moveFrame(fromIndex, toIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentFrameIndex = function (index) { - this.piskelController.setCurrentFrameIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectNextFrame = function () { - this.piskelController.selectNextFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectPreviousFrame = function () { - this.piskelController.selectPreviousFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentLayerIndex = function (index) { - this.piskelController.setCurrentLayerIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectLayer = function (layer) { - this.piskelController.selectLayer(layer); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.renameLayerAt = function (index, name) { - this.raiseSaveStateEvent_(this.piskelController.renameLayerAt, [index, name]); - this.piskelController.renameLayerAt(index, name); - }; - - ns.PublicPiskelController.prototype.createLayer = function (name) { - this.raiseSaveStateEvent_(this.piskelController.createLayer, [name]); - this.piskelController.createLayer(name); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.mergeDownLayerAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.mergeDownLayerAt, [index]); - this.piskelController.mergeDownLayerAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerUp = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerUp, []); - this.piskelController.moveLayerUp(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerDown = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerDown, []); - this.piskelController.moveLayerDown(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.raiseSaveStateEvent_(this.piskelController.removeLayerAt, [currentLayerIndex]); - this.piskelController.removeLayerAt(currentLayerIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.getCurrentLayerIndex = function () { - return this.piskelController.getCurrentLayerIndex(); - }; - - ns.PublicPiskelController.prototype.getCurrentFrameIndex = function () { - return this.piskelController.currentFrameIndex; - }; - - ns.PublicPiskelController.prototype.getPiskel = function () { - return this.piskelController.piskel; - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT, - scope : this, - replay : { - fn : fn, - args : args - } - }); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - this.dragHandler = new ns.drawing.DragHandler(this); - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = pskl.rendering.OnionSkinRenderer.createInContainer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChange_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(function () { - this.afterWindowResize_(); - this.resetZoom_(); - }.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isIE11) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChange_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - $.publish(Events.MOUSE_EVENT, [event, this]); - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - - this.isClicked = true; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - this.dragHandler.startDrag(event.clientX, event.clientY); - } else { - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - $.publish(Events.TOOL_PRESSED); - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.getSpriteCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - if(this.currentMouseButton_ == Constants.MIDDLE_BUTTON) { - this.dragHandler.updateDrag(x, y); - } else { - $.publish(Events.MOUSE_EVENT, [event, this]); - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - } else { - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - // Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40 - var delta; - if (pskl.utils.UserAgent.isChrome) { - delta = event.wheelDeltaY; - } else if (pskl.utils.UserAgent.isIE11) { - delta = event.wheelDelta; - } else if (pskl.utils.UserAgent.isFirefox) { - delta = -40 * event.deltaY; - } - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - if(this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (this.dragHandler.isDragging()) { - this.dragHandler.stopDrag(); - } else if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) { - return this.renderer.reverseCoordinates(spriteX, spriteY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.getAvailableHeight_(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.getAvailableWidth_(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.getOffset = function () { - return this.compositeRenderer.getOffset(); - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.drawing'); - - /** - * Multiplier applied between the mouse movement and viewport movement - * @type {Number} - */ - var MULTIPLIER = 2; - - /** - * Dedicated handler to drag the drawing canvas using the mouse - * Will store the initial coordinates as well as the status of the drag - * @param {DrawingController} drawingController - */ - ns.DragHandler = function (drawingController) { - this.drawingController = drawingController; - - this.isDragging_ = false; - this.updateOrigin_(-1, -1); - }; - - /** - * Initialize a drag session. - * @param {Number} x : x coordinate of the mouse event that initiated the drag - * @param {Number} y : y coordinate of the mouse event that initiated the drag - */ - ns.DragHandler.prototype.startDrag = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - }; - - /** - * Update the drag status - * @param {Number} x : x coordinate of the mouse event that triggered the update - * @param {Number} y : y coordinate of the mouse event that triggered the update - */ - ns.DragHandler.prototype.updateDrag = function (x, y) { - var currentOffset = this.drawingController.getOffset(); - var offset = this.calculateOffset_(x, y); - if (currentOffset.y !== offset.y || currentOffset.x !== offset.x) { - this.isDragging_ = true; - this.drawingController.setOffset(offset.x, offset.y); - - // retrieve the updated coordinates after moving the sprite - // and store them as the new drag origin - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - } - }; - - /** - * Stop the drag session - */ - ns.DragHandler.prototype.stopDrag = function () { - this.isDragging_ = false; - this.origin = null; - }; - - /** - * Will return true if the drag handler effectively MOVED the offset - * during the current drag session - */ - ns.DragHandler.prototype.isDragging = function () { - return this.isDragging_; - }; - - ns.DragHandler.prototype.calculateOffset_ = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - var currentOffset = this.drawingController.getOffset(); - - var offset = { - x : currentOffset.x - MULTIPLIER * (coords.x - this.origin.x), - y : currentOffset.y - MULTIPLIER * (coords.y - this.origin.y) - }; - - return offset; - }; - - ns.DragHandler.prototype.updateOrigin_ = function (x, y) { - this.origin = this.origin || {}; - this.origin.x = x; - this.origin.y = y; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.PreviewFilmController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.PreviewFilmController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.PreviewFilmController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.PreviewFilmController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.PreviewFilmController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.PreviewFilmController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.PreviewFilmController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.PreviewFilmController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - var height = this.zoom * this.piskelController.getCurrentFrame().getHeight(); - var horizontalMargin = (Constants.PREVIEW_FILM_SIZE - height) / 2; - canvasContainer.style.marginTop = horizontalMargin + 'px'; - - var width = this.zoom * this.piskelController.getCurrentFrame().getWidth(); - var verticalMargin = (Constants.PREVIEW_FILM_SIZE - width) / 2; - canvasContainer.style.marginLeft = verticalMargin + 'px'; - canvasContainer.style.marginRight = verticalMargin + 'px'; - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.PreviewFilmController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.PreviewFilmController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.utils.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.PreviewFilmController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var frameSize = Math.max(frame.getHeight(), frame.getWidth()); - - return Constants.PREVIEW_FILM_SIZE/frameSize; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - this.updateButtonStatus_(); - }; - - ns.LayersListController.prototype.updateButtonStatus_ = function () { - var layers = this.piskelController.getLayers(); - var currentLayer = this.piskelController.getCurrentLayer(); - var index = this.piskelController.getCurrentLayerIndex(); - - var isLast = index === 0; - var isOnly = layers.length === 1; - var isFirst = index === layers.length - 1; - - this.toggleButtonDisabledState_('up', isFirst); - this.toggleButtonDisabledState_('down', isLast); - this.toggleButtonDisabledState_('merge', isLast); - this.toggleButtonDisabledState_('delete', isOnly); - }; - - ns.LayersListController.prototype.toggleButtonDisabledState_ = function (buttonAction, isDisabled) { - var button = document.querySelector('.layers-button[data-action="'+buttonAction+'"]'); - if (isDisabled) { - button.setAttribute('disabled', 'disabled'); - } else { - button.removeAttribute('disabled'); - } - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } - }; - - ns.LayersListController.prototype.renameCurrentLayer_ = function () { - var layer = this.piskelController.getCurrentLayer(); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.mergeDownCurrentLayer_ = function () { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.mergeDownLayerAt(index); - this.renderLayerList_(); - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } else if (action == 'merge') { - this.mergeDownCurrentLayer_(); - } else if (action == 'edit') { - this.renameCurrentLayer_(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.AnimatedPreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.renderFlag = true; - - this.fpsRangeInput = $('#preview-fps'); - this.fpsCounterDisplay = $('#display-fps'); - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - }; - - ns.AnimatedPreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this)); - document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - $.subscribe(Events.TOOL_RELEASED, this.setRenderFlag_.bind(this, true)); - $.subscribe(Events.TOOL_PRESSED, this.setRenderFlag_.bind(this, false)); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - this.updateContainerDimensions_(); - }; - - ns.AnimatedPreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.AnimatedPreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.AnimatedPreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.AnimatedPreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.AnimatedPreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt(this.fpsRangeInput[0].value, 10)); - - }; - - ns.AnimatedPreviewController.prototype.setFPS = function (fps) { - if (typeof fps === 'number') { - this.fps = fps; - this.fpsRangeInput.val(this.fps); - this.fpsRangeInput.blur(); - this.fpsCounterDisplay.html(this.fps + ' FPS'); - } - }; - - ns.AnimatedPreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.AnimatedPreviewController.prototype.render = function (delta) { - if (this.renderFlag) { - this.elapsedTime += delta; - if (this.fps === 0) { - this._renderSelectedFrame(); - } else { - this._renderCurrentAnimationFrame(); - } - } - }; - - ns.AnimatedPreviewController.prototype._renderSelectedFrame = function (delta) { - // the selected frame is the currentFrame from the PiskelController perspective - var selectedFrameIndex = this.piskelController.getCurrentFrameIndex(); - var selectedFrame = this.piskelController.getFrameAt(selectedFrameIndex); - this.renderer.render(selectedFrame); - }; - - ns.AnimatedPreviewController.prototype._renderCurrentAnimationFrame = function (delta) { - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (index != this.currentIndex) { - this.currentIndex = index; - if (!this.piskelController.hasFrameAt(this.currentIndex)) { - this.currentIndex = 0; - this.elapsedTime = 0; - } - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var hZoom = PREVIEW_SIZE / frame.getHeight(), - wZoom = PREVIEW_SIZE / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.AnimatedPreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.AnimatedPreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + 'px'; - containerEl.style.width = width + 'px'; - - var horizontalMargin = (PREVIEW_SIZE - height) / 2; - containerEl.style.marginTop = horizontalMargin + 'px'; - containerEl.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (PREVIEW_SIZE - width) / 2; - containerEl.style.marginLeft = verticalMargin + 'px'; - containerEl.style.marginRight = verticalMargin + 'px'; - }; - - ns.AnimatedPreviewController.prototype.setRenderFlag_ = function (bool) { - this.renderFlag = bool; - }; - - ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, animationController, drawingController, container) { - this.piskelController = piskelController; - this.animationController = animationController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - this.isVisible = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.minimapEl = document.createElement('DIV'); - this.minimapEl.className = 'minimap-crop-frame'; - this.minimapEl.style.display = 'none'; - $(this.container).append(this.minimapEl); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var verticalRatio = this.getVerticalRatio_(); - var horizontalRatio = this.getHorizontalRatio_(); - if (verticalRatio > 1 || horizontalRatio > 1) { - this.displayMinimap_(); - } else { - this.hideMinimap_(); - } - }; - - ns.MinimapController.prototype.displayMinimap_ = function () { - var minimapSize = this.getMinimapSize_(); - var previewSize = this.getPreviewSize_(); - - var containerHeight = this.container.height(); - var containerWidth = this.container.width(); - - // offset(x, y) in frame pixels - var offset = this.drawingController.getRenderer().getOffset(); - - // the preview is centered in a square container - // if the sprite is not a square, a margin is needed on the appropriate coordinate - // before adding the offset coming from the drawing area - var leftMargin = (containerWidth - Math.max(minimapSize.width, previewSize.width))/2; - var leftOffset = offset.x * this.animationController.getZoom(); - var left = leftMargin + leftOffset; - - var topMargin = (containerHeight - Math.max(minimapSize.height, previewSize.height))/2; - var topOffset = offset.y * this.animationController.getZoom(); - var top = topMargin + topOffset; - - this.minimapEl.style.display = 'block'; - this.minimapEl.style.width = Math.min(minimapSize.width, containerWidth) + 'px'; - this.minimapEl.style.height = Math.min(minimapSize.height, containerHeight) + 'px'; - this.minimapEl.style.left = Math.max(0, left) + 'px'; - this.minimapEl.style.top = Math.max(0, top) + 'px'; - - this.isVisible = true; - }; - - ns.MinimapController.prototype.getMinimapSize_ = function () { - // Calculate the ratio to translate drawing area sizes to animated preview sizes - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var animatedPreviewZoom = this.animationController.getZoom(); - var ratio = drawingAreaZoom / animatedPreviewZoom; - - var displaySize = this.drawingController.getRenderer().getDisplaySize(); - var minimapWidth = displaySize.width / ratio; - var minimapHeight = displaySize.height / ratio; - - return { - width : minimapWidth, - height: minimapHeight - }; - }; - - ns.MinimapController.prototype.getPreviewSize_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewWidth = frame.getWidth() * this.animationController.getZoom(); - var previewHeight = frame.getHeight() * this.animationController.getZoom(); - - return { - width : previewWidth, - height: previewHeight - }; - }; - - ns.MinimapController.prototype.hideMinimap_ = function () { - this.minimapEl.style.display = 'none'; - this.isVisible = false; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isVisible && this.isClicked) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.animationController.getCoordinates(x, y); - - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / this.getHorizontalRatio_(); - var height = frameHeight / this.getVerticalRatio_(); - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getVerticalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalHeight = frame.getHeight() * drawingAreaZoom; - var frameDisplayHeight = this.drawingController.getRenderer().getDisplaySize().height; - - return frameTotalHeight / frameDisplayHeight; - }; - - ns.MinimapController.prototype.getHorizontalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalWidth = frame.getWidth() * drawingAreaZoom; - var frameDisplayWidth = this.drawingController.getRenderer().getDisplaySize().width; - - return frameTotalWidth / frameDisplayWidth; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()), - toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()), - toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()), - toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()), - toDescriptor('move', 'M', new pskl.tools.drawing.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - - $.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.tools.drawing.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) { - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - return pskl.utils.Array.find(this.tools, function (tool) { - return tool.instance.toolId == toolId; - }); - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var html = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - html += this.toolIconRenderer.render(tool.instance, tool.shortcut); - } - $('#tools-container').html(html); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteService = pskl.app.paletteService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - - var createPaletteButton_ = document.querySelector('.create-palette-button'); - var editPaletteButton_ = document.querySelector('.edit-palette-button'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - editPaletteButton_.addEventListener('click', this.onEditPaletteClick_.bind(this)); - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - - pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this)); - pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this)); - - this.fillPaletteList(); - this.updateFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = this.paletteService.getPalettes(); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.colorPaletteSelect_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - - var colors = this.getSelectedPaletteColors_(); - - if (colors.length > 0) { - var html = colors.map(function (color, index) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - } else { - this.colorListContainer_.innerHTML = pskl.utils.Template.get('palettes-list-no-colors-partial'); - } - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var palette = this.getSelectedPalette_(); - if (palette) { - colors = palette.getColors(); - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.getSelectedPalette_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - return this.paletteService.getPaletteById(paletteId); - }; - - ns.PalettesListController.prototype.selectNextColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() + 1); - }; - - ns.PalettesListController.prototype.selectPreviousColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() - 1); - }; - - ns.PalettesListController.prototype.getCurrentColorIndex_ = function () { - var currentIndex = 0; - var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME); - if (selectedColor) { - currentIndex = parseInt(selectedColor.dataset.colorIndex, 10); - } - return currentIndex; - }; - - ns.PalettesListController.prototype.selectColor_ = function (index) { - var colors = this.getSelectedPaletteColors_(); - var color = colors[index]; - if (color) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } - }; - - ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.SELECTED_PALETTE) { - this.updateFromUserSettings(); - } - }; - - ns.PalettesListController.prototype.updateFromUserSettings = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - this.fillColorListContainer(); - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - this.selectPalette(paletteId); - this.colorPaletteSelect_.blur(); - }; - - ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); - }; - - ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : paletteId - }); - }; - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.updateFromUserSettings(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.ProgressBarController = function () { - this.template = pskl.utils.Template.get('progress-bar-template'); - this.progressBar = null; - this.progressBarStatus = null; - - this.showProgressTimer_ = 0; - }; - - ns.ProgressBarController.prototype.init = function () { - $.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this)); - $.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this)); - $.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this)); - }; - - ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) { - this.removeProgressBar_(); - this.showProgressTimer_ = window.setTimeout(this.onTimerExpired_.bind(this, progressInfo), 300); - }; - - ns.ProgressBarController.prototype.onTimerExpired_ = function (progressInfo) { - var progressBarHtml = pskl.utils.Template.replace(this.template, { - name : progressInfo.name, - status : 0 - }); - - var progressBarEl = pskl.utils.Template.createFromHTML(progressBarHtml); - document.body.appendChild(progressBarEl); - - this.progressBar = document.querySelector('.progress-bar'); - this.progressBarStatus = document.querySelector('.progress-bar-status'); - }; - - ns.ProgressBarController.prototype.updateProgress_ = function (event, progressInfo) { - if (this.progressBar && this.progressBarStatus) { - var progress = progressInfo.progress; - var width = this.progressBar.offsetWidth; - var progressWidth = width - ((progress * width) / 100); - this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; - this.progressBarStatus.innerHTML = progress + '%'; - } - }; - - ns.ProgressBarController.prototype.hideProgress_ = function (event, progressInfo) { - if (this.showProgressTimer_) { - window.clearTimeout(this.showProgressTimer_); - } - this.removeProgressBar_(); - }; - - ns.ProgressBarController.prototype.removeProgressBar_ = function () { - var progressBarContainer = document.querySelector('.progress-bar-container'); - if (progressBarContainer) { - progressBarContainer.parentNode.removeChild(progressBarContainer); - this.progressBar = null; - this.progressBarStatus = null; - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - - message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this)); - if (messageInfo.behavior) { - messageInfo.behavior(message); - } - - if (messageInfo.hideDelay) { - window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.TransformationsController = function () { - - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('flip', '', new pskl.tools.transform.Flip()), - toDescriptor('rotate', '', new pskl.tools.transform.Rotate()), - toDescriptor('clone', '', new pskl.tools.transform.Clone()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - ns.TransformationsController.prototype.init = function () { - var container = document.querySelector('.transformations-container'); - this.toolsContainer = container.querySelector('.tools-wrapper'); - container.addEventListener('click', this.onTransformationClick.bind(this)); - this.createToolsDom_(); - }; - - - ns.TransformationsController.prototype.onTransformationClick = function (evt) { - var toolId = evt.target.dataset.toolId; - this.tools.forEach(function (tool) { - if (tool.instance.toolId === toolId) { - tool.instance.apply(evt); - } - }.bind(this)); - }; - - ns.TransformationsController.prototype.createToolsDom_ = function() { - var html = this.tools.reduce(function (p, tool) { - return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left'); - }.bind(this), ''); - this.toolsContainer.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - /** - * @public - */ - ns.ApplicationSettingsController.prototype.init = function() { - // Highlight selected background picker: - var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - $('#background-picker-wrapper') - .find('.background-picker[data-background-class=' + backgroundClass + ']') - .addClass('selected'); - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - $('#grid-width').val(gridWidth); - $('#grid-width').change(this.onGridWidthChange.bind(this)); - - // Handle canvas background changes: - $('#background-picker-wrapper').click(this.onBackgroundClick.bind(this)); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange = function (evt) { - var width = $('#grid-width').val(); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, parseInt(width, 10)); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick = function (evt) { - var target = $(evt.target).closest('.background-picker'); - if (target.length) { - var backgroundClass = target.data('background-class'); - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); - - $('.background-picker').removeClass('selected'); - target.addClass('selected'); - } - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = $(".gif-upload-button"); - this.uploadButton.click(this.onUploadButtonClick_.bind(this)); - - this.downloadButton = $(".gif-download-button"); - this.downloadButton.click(this.onDownloadButtonClick_.bind(this)); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.originalEvent.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.uploadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.downloadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.downloadImageData_ = function (imageData) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.GifExportController.prototype.uploadImageData_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this), this.onImageUploadFailed_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.onImageUploadFailed_ = function (event, xhr) { - if (xhr.status === 500) { - $.publish(Events.SHOW_NOTIFICATION, [{ - "content": "Upload failed : " + xhr.responseText, - "hideDelay" : 5000 - }]); - } - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 5, - quality: 1, - width: this.piskelController.getWidth() * zoom, - height: this.piskelController.getHeight() * zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Building animated GIF ...'}]); - gif.on('progress', function(percentage) { - $.publish(Events.UPDATE_PROGRESS, [{"progress": (percentage*100).toFixed(1)}]); - }.bind(this)); - - gif.on('finished', function(blob) { - $.publish(Events.HIDE_PROGRESS); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelector(".png-export-preview"); - this.pngFilePrefixInput = document.getElementById('zip-prefix-name'); - this.pngFilePrefixInput.value = 'sprite_'; - - document.querySelector(".png-download-button").addEventListener('click', this.onPngDownloadButtonClick_.bind(this)); - - document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this)); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var basename = this.pngFilePrefixInput.value; - var filename = basename + (i+1) + ".png"; - zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.ResizeController = function (piskelController) { - var resizeCanvasContainer = document.querySelector('.resize-canvas'); - this.resizeCanvasController = new ns.ResizeCanvasController(piskelController, resizeCanvasContainer); - - var resizeContentContainer = document.querySelector('.resize-content'); - this.resizeContentController = new ns.ResizeContentController(piskelController, resizeContentContainer); - }; - - ns.ResizeController.prototype.init = function () { - this.resizeCanvasController.init(); - this.resizeContentController.init(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.AbstractResizeController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - }; - - ns.AbstractResizeController.prototype.init = function () { - this.widthInput = this.container.querySelector('[name="resize-width"]'); - this.heightInput = this.container.querySelector('[name="resize-height"]'); - - this.widthInput.value = this.piskelController.getWidth(); - this.heightInput.value = this.piskelController.getHeight(); - - this.widthInput.addEventListener('keyup', this.onSizeInputKeyUp_.bind(this)); - this.heightInput.addEventListener('keyup', this.onSizeInputKeyUp_.bind(this)); - - this.cancelButton = this.container.querySelector('.resize-cancel-button'); - this.cancelButton.addEventListener('click', this.onCancelButtonClicked_.bind(this)); - - this.resizeForm = this.container.querySelector('form'); - this.resizeForm.addEventListener('submit', this.onResizeFormSubmit_.bind(this)); - - this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox'); - this.maintainRatioCheckbox.addEventListener('change', this.onMaintainRatioChange_.bind(this)); - - this.lastInput = this.widthInput; - }; - - ns.AbstractResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.preventDefault(); - - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - - ns.AbstractResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.AbstractResizeController.prototype.resizeFrame_ = Constants.ABSTRACT_FUNCTION; - - ns.AbstractResizeController.prototype.onCancelButtonClicked_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - ns.AbstractResizeController.prototype.onMaintainRatioChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.synchronizeSizeInputs_(this.lastInput); - } - }; - - ns.AbstractResizeController.prototype.onSizeInputKeyUp_ = function (evt) { - var target = evt.target; - if (this.maintainRatioCheckbox.checked) { - this.synchronizeSizeInputs_(target); - } - this.lastInput = target; - }; - - /** - * Based on the value of the provided sizeInput (considered as emitter) - * update the value of the other sizeInput to match the current width/height ratio - * @param {HTMLElement} origin either widthInput or heightInput - */ - ns.AbstractResizeController.prototype.synchronizeSizeInputs_ = function (sizeInput) { - var value = parseInt(sizeInput.value, 10); - if (isNaN(value)) { - value = 0; - } - - var height = this.piskelController.getHeight(), - width = this.piskelController.getWidth(); - - if (sizeInput === this.widthInput) { - this.heightInput.value = Math.round(value * height/width); - } else if (sizeInput === this.heightInput) { - this.widthInput.value = Math.round(value * width/height); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - var ORIGIN = { - TOPLEFT : 'TOPLEFT', - TOP : 'TOP', - TOPRIGHT : 'TOPRIGHT', - MIDDLELEFT : 'MIDDLELEFT', - MIDDLE : 'MIDDLE', - MIDDLERIGHT : 'MIDDLERIGHT', - BOTTOMLEFT : 'BOTTOMLEFT', - BOTTOM : 'BOTTOM', - BOTTOMRIGHT : 'BOTTOMRIGHT' - }; - - ns.ResizeCanvasController = function (piskelController, container) { - this.superclass.constructor.call(this, piskelController, container); - this.origin = ORIGIN.TOPLEFT; - }; - - pskl.utils.inherit(ns.ResizeCanvasController, ns.AbstractResizeController); - - ns.ResizeCanvasController.prototype.init = function () { - this.superclass.init.call(this); - - this.resizeOrigin = document.querySelector('.resize-origin-container'); - this.resizeOrigin.addEventListener('click', this.onResizeOriginClick_.bind(this)); - - this.setOrigin_(ORIGIN.TOPLEFT); - }; - - /****************/ - /* RESIZE LOGIC */ - /****************/ - - ns.ResizeCanvasController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.widthInput.value, 10); - var height = parseInt(this.heightInput.value, 10); - - var resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - var translated = this.translateCoordinates_(x, y, frame, resizedFrame); - if (resizedFrame.containsPixel(translated.x, translated.y)) { - resizedFrame.setPixel(translated.x, translated.y, color); - } - }.bind(this)); - - return resizedFrame; - }; - - ns.ResizeCanvasController.prototype.translateCoordinates_ = function (x, y, frame, resizedFrame) { - return { - x : this.translateX_(x, frame.width, resizedFrame.width), - y : this.translateY_(y, frame.height, resizedFrame.height) - }; - }; - - ns.ResizeCanvasController.prototype.translateX_ = function (x, width, resizedWidth) { - if (this.origin.indexOf('LEFT') != -1) { - return x; - } else if (this.origin.indexOf('RIGHT') != -1) { - return x - (width - resizedWidth); - } else { - return x - Math.round((width - resizedWidth)/2); - } - }; - - ns.ResizeCanvasController.prototype.translateY_ = function (y, height, resizedHeight) { - if (this.origin.indexOf('TOP') != -1) { - return y; - } else if (this.origin.indexOf('BOTTOM') != -1) { - return y - (height - resizedHeight); - } else { - return y - Math.round((height - resizedHeight)/2); - } - }; - - /*****************/ - /* ANCHOR WIDGET */ - /*****************/ - - ns.ResizeCanvasController.prototype.onResizeOriginClick_ = function (evt) { - var origin = evt.target.dataset.origin; - if (origin && ORIGIN[origin]) { - this.setOrigin_(origin); - } - }; - - ns.ResizeCanvasController.prototype.setOrigin_ = function (origin) { - this.origin = origin; - var previous = document.querySelector('.resize-origin-option.selected'); - if (previous) { - previous.classList.remove('selected'); - } - - var selected = document.querySelector('.resize-origin-option[data-origin="' + origin + '"]'); - if (selected) { - selected.classList.add('selected'); - this.refreshNeighbors_(selected); - } - }; - - ns.ResizeCanvasController.prototype.refreshNeighbors_ = function (selected) { - var options = document.querySelectorAll('.resize-origin-option'); - for (var i = 0 ; i < options.length ; i++) { - options[i].removeAttribute('data-neighbor'); - } - - var selectedIndex = Array.prototype.indexOf.call(options, selected); - - this.setNeighborhood_(options[selectedIndex - 1], 'left'); - this.setNeighborhood_(options[selectedIndex + 1], 'right'); - this.setNeighborhood_(options[selectedIndex - 3], 'top'); - this.setNeighborhood_(options[selectedIndex + 3], 'bottom'); - }; - - ns.ResizeCanvasController.prototype.setNeighborhood_ = function (el, neighborhood) { - var origin = this.origin.toLowerCase(); - var isNeighborhoodValid = origin.indexOf(neighborhood) === -1; - if (isNeighborhoodValid) { - el.setAttribute('data-neighbor', neighborhood); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.ResizeContentController = function (piskelController, container) { - this.superclass.constructor.call(this, piskelController, container); - }; - - pskl.utils.inherit(ns.ResizeContentController, ns.AbstractResizeController); - - ns.ResizeContentController.prototype.init = function () { - this.superclass.init.call(this); - }; - - ns.ResizeContentController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.widthInput.value, 10); - var height = parseInt(this.heightInput.value, 10); - return pskl.utils.FrameUtils.resize(frame, width, height, false); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - - // Only available in app-engine mode ... - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = $('#save-online-status'); - - this.saveFileStatus = $('#save-file-status'); - this.timestamp = new Date(); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = $('#save-description'); - this.descriptionInput.val(descriptor.description); - - this.isPublicCheckbox = $('input[name=save-public-checkbox]'); - this.isPublicCheckbox.prop('checked', descriptor.isPublic); - - this.saveFileButton = $('#save-file-button'); - this.saveFileButton.click(this.saveFile_.bind(this)); - - this.saveLocalButton = $('#save-browser-button'); - this.saveLocalButton.click(this.saveLocal_.bind(this)); - - this.saveOnlineButton = $('#save-online-button'); - this.saveOnlineButton.click(this.saveOnline_.bind(this)); - - this.saveForm = $('form[name=save-form]'); - this.saveForm.submit(this.onSaveFormSubmit_.bind(this)); - - this.nameInput = $('#save-name'); - this.nameInput.val(descriptor.name); - this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this)); - - if (!pskl.app.isLoggedIn()) { - this.saveOnlineButton.hide(); - $('.save-public-section').hide(); - this.saveOnlineStatus.html(pskl.utils.Template.get('save-please-login-partial')); - } else { - this.saveOnlineStatus.html(pskl.utils.Template.get('save-online-status-partial')); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.html(pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - })); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.html('Saving ...'); - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.val(); - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.val(); - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.html(''); - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - this.importedImage_ = null; - }; - - ns.ImportController.prototype.init = function () { - this.browseLocalButton = document.querySelector('.browse-local-button'); - this.browseLocalButton.addEventListener('click', this.onBrowseLocalClick_.bind(this)); - - this.hiddenFileInput = $('[name=file-upload-input]'); - this.hiddenFileInput.change(this.onFileUploadChange_.bind(this)); - - this.fileInputButton = $('.file-input-button'); - this.fileInputButton.click(this.onFileInputClick_.bind(this)); - - this.hiddenOpenPiskelInput = $('[name=open-piskel-input]'); - this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this)); - - this.openPiskelInputButton = $('.open-piskel-button'); - this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this)); - - this.prevSessionContainer = $('.previous-session'); - this.previousSessionTemplate_ = pskl.utils.Template.get("previous-session-info-template"); - this.fillRestoreSession_(); - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - var files = this.hiddenOpenPiskelInput.get(0).files; - if (files.length == 1) { - this.openPiskelFile_(files[0]); - } - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function (file) { - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - this.closeDrawer_(); - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.get(0).files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.fillRestoreSession_ = function () { - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var info = { - name : previousInfo.name, - date : pskl.utils.DateUtils.format(previousInfo.date, "{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}") - }; - - this.prevSessionContainer.html(pskl.utils.Template.replace(this.previousSessionTemplate_, info)); - $(".restore-session-button").click(this.onRestorePreviousSessionClick_.bind(this)); - } else { - this.prevSessionContainer.html("No piskel backup was found on this browser."); - } - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.resize.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.exportimage.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - (new settings[setting].controller(this.piskelController)).init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - this.currentSetting = setting; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - this.destroy(); - $.publish(Events.DIALOG_HIDE); - }; - - ns.AbstractDialogController.prototype.setTitle = function (title) { - var dialogTitle = document.querySelector('.dialog-title'); - if (dialogTitle) { - dialogTitle.innerText = title; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteController = function (piskelController) { - this.paletteService = pskl.app.paletteService; - this.paletteImportService = pskl.app.paletteImportService; - }; - - pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - - ns.CreatePaletteController.prototype.init = function (paletteId) { - this.superclass.init.call(this); - - this.hiddenFileInput = document.querySelector('.create-palette-import-input'); - this.nameInput = document.querySelector('input[name="palette-name"]'); - - var buttonsContainer = document.querySelector('.create-palette-actions'); - var deleteButton = document.querySelector('.create-palette-delete'); - var downloadButton = document.querySelector('.create-palette-download-button'); - var importFileButton = document.querySelector('.create-palette-import-button'); - - this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); - this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - - buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this)); - downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this)); - importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); - - var colorsListContainer = document.querySelector('.colors-container'); - this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer); - - var palette; - var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID; - if (paletteId && !isCurrentColorsPalette) { - importFileButton.style.display = 'none'; - this.setTitle('Edit Palette'); - - var paletteObject = this.paletteService.getPaletteById(paletteId); - palette = pskl.model.Palette.fromObject(paletteObject); - } else { - downloadButton.style.display = 'none'; - deleteButton.style.display = 'none'; - this.setTitle('Create Palette'); - - var uuid = pskl.utils.Uuid.generate(); - if (isCurrentColorsPalette) { - palette = new pskl.model.Palette(uuid, 'Current colors clone', this.getCurrentColors_()); - } else { - palette = new pskl.model.Palette(uuid, 'New palette', []); - } - } - - this.setPalette_(palette); - }; - - ns.CreatePaletteController.prototype.getCurrentColors_ = function () { - var palette = this.paletteService.getPaletteById(Constants.CURRENT_COLORS_PALETTE_ID); - return palette.getColors(); - }; - - ns.CreatePaletteController.prototype.setPalette_ = function (palette) { - this.palette = palette; - this.nameInput.value = pskl.utils.unescapeHtml(palette.name); - this.colorsListWidget.setColors(palette.getColors()); - }; - - ns.CreatePaletteController.prototype.destroy = function () { - this.colorsListWidget.destroy(); - this.nameInput = null; - }; - - ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) { - var target = evt.target; - if (target.dataset.action === 'submit') { - this.saveAndSelectPalette_(); - } else if (target.dataset.action === 'cancel') { - this.closeDialog(); - } else if (target.dataset.action === 'delete') { - this.deletePalette_(); - } - }; - - ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function () { - this.palette.setColors(this.colorsListWidget.getColors()); - this.paletteService.savePalette(this.palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, this.palette.id); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.deletePalette_ = function () { - if (window.confirm('Are you sure you want to delete palette ' + this.palette.name)) { - this.paletteService.deletePaletteById(this.palette.id); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, Constants.CURRENT_COLORS_PALETTE_ID); - this.closeDialog(); - } - }; - - ns.CreatePaletteController.prototype.onDownloadButtonClick_ = function () { - var paletteWriter = new pskl.service.palette.PaletteGplWriter(this.palette); - var paletteAsString = paletteWriter.write(); - - pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.palette.name + '.gpl'); - }.bind(this), "application/json"); - }; - - ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { - this.hiddenFileInput.click(); - }; - - ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - this.paletteImportService.read(files[0], this.setPalette_.bind(this), this.displayErrorMessage_.bind(this)); - } - }; - - ns.CreatePaletteController.prototype.displayErrorMessage_ = function (message) { - message = "Could not import palette : " + message; - $.publish(Events.SHOW_NOTIFICATION, [{"content": message}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { - this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (image) { - this.importedImage_ = image; - - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.utils.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'create-palette' : { - template : 'templates/dialogs/create-palette.html', - controller : ns.CreatePaletteController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette')); - - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.classList.add(dialogId); - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - var DEFAULT_COLOR = '#000000'; - - ns.ColorsList = function (container) { - this.selectedIndex = -1; - this.palette = new pskl.model.Palette('tmp', 'tmp', []); - this.container = container; - - this.colorsList = this.container.querySelector('.colors-list'); - this.colorPreviewEl = this.container.querySelector('.color-preview'); - - $(container).sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onColorDrop_.bind(this), - items: '.create-palette-color' - }); - - this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - - var colorPickerContainer = container.querySelector('.color-picker-container'); - this.hslRgbColorPicker = new pskl.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); - this.hslRgbColorPicker.init(); - }; - - ns.ColorsList.prototype.setColors = function (colors) { - if (colors.length === 0) { - colors.push(DEFAULT_COLOR); - } - - this.palette.setColors(colors); - - this.selectColor_(0); - this.refresh_(); - }; - - ns.ColorsList.prototype.getColors = function () { - return this.palette.getColors(); - }; - - ns.ColorsList.prototype.destroy = function () { - this.hslRgbColorPicker.destroy(); - this.container = null; - this.colorsList = null; - this.colorPreviewEl = null; - }; - - /** - * Lightweight refresh only changing the color of one element of the palette color list - */ - ns.ColorsList.prototype.refreshColorElement_ = function (index) { - var color = this.palette.get(this.selectedIndex); - var element = document.querySelector('[data-palette-index="'+index+'"]'); - if (element) { - element.style.background = color; - element.classList.toggle('light-color', this.isLight_(color)); - } - }; - - ns.ColorsList.prototype.onColorContainerClick_ = function (evt) { - var target = evt.target; - if (target.classList.contains('create-palette-color')) { - this.onPaletteColorClick_(evt, target); - } else if (target.classList.contains('create-palette-new-color')) { - this.onNewColorClick_(evt, target); - } else if (target.classList.contains('create-palette-remove-color')) { - this.onRemoveColorClick_(evt, target); - } - this.refresh_(); - }; - - ns.ColorsList.prototype.onColorUpdated_ = function (color) { - var rgbColor = color.toRgbString(); - this.colorPreviewEl.style.background = rgbColor; - if (this.palette) { - this.palette.set(this.selectedIndex, rgbColor); - this.refreshColorElement_(this.selectedIndex); - } - }; - - ns.ColorsList.prototype.onPaletteColorClick_ = function (evt, target) { - var index = parseInt(target.dataset.paletteIndex,10); - this.selectColor_(index); - }; - - ns.ColorsList.prototype.onRemoveColorClick_ = function (evt, target) { - var colorElement = target.parentNode; - var index = parseInt(colorElement.dataset.paletteIndex,10); - this.removeColor_(index); - }; - - ns.ColorsList.prototype.onNewColorClick_ = function (evt, target) { - var newColor = this.palette.get(this.selectedIndex) || '#000000'; - this.palette.add(newColor); - this.selectColor_(this.palette.size()-1); - }; - - ns.ColorsList.prototype.refresh_ = function () { - var html = ""; - var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.getColors(); - - colors.forEach(function (color, index) { - var isSelected = (index === this.selectedIndex); - - html += pskl.utils.Template.replace(tpl, { - 'color':color, index:index, - ':selected':isSelected, - ':light-color':this.isLight_(color) - }); - }.bind(this)); - - html += '
      • +
      • '; - - this.colorsList.innerHTML = html; - }; - - ns.ColorsList.prototype.selectColor_ = function (index) { - this.selectedIndex = index; - this.hslRgbColorPicker.setColor(this.palette.get(index)); - }; - - ns.ColorsList.prototype.removeColor_ = function (index) { - this.palette.removeAt(index); - this.refresh_(); - }; - - ns.ColorsList.prototype.isLight_ = function (color) { - var rgb = window.tinycolor(color).toRgb(); - return rgb.r+rgb.b+rgb.g > 128*3; - }; - - ns.ColorsList.prototype.onColorDrop_ = function (evt, drop) { - var colorElement = drop.item.get(0); - - var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); - var newIndex = $('.create-palette-color').index(drop.item); - this.palette.move(oldIndex, newIndex); - - this.selectedIndex = newIndex; - - this.refresh_(); - }; -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { - this.container = container; - this.colorUpdatedCallback = colorUpdatedCallback; - - this.tinyColor = null; - this.hsvColor = null; - this.rgbColor = null; - - this.lastInputTimestamp_ = 0; - }; - - ns.HslRgbColorPicker.prototype.init = function () { - var isChromeOrFirefox = pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isFirefox; - var changeEvent = isChromeOrFirefox ? 'input' : 'change'; - this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this)); - this.container.addEventListener('keydown', this.onKeydown_.bind(this)); - this.container.addEventListener('focusout', this.onBlur_.bind(this)); - - this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); - - $(this.spectrumEl).spectrum({ - flat: true, - showButtons: false, - move : this.setColor.bind(this), - change : this.setColor.bind(this) - }); - - this.setColor("#000000"); - }; - - ns.HslRgbColorPicker.prototype.destroy = function () { - this.container = null; - this.spectrumEl = null; - }; - - ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) { - var target = evt.target; - if (target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = target.value; - - this.updateColor_(value, model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.onKeydown_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - - if (model === 'rgb' || model === 'hsv') { - var increment = this.getIncrement_(evt); - if (increment) { - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - this.updateColor_(value + increment, model, dimension); - } - } - } - }; - - ns.HslRgbColorPicker.prototype.getIncrement_ = function (evt) { - var increment = 0; - var key = pskl.service.keyboard.KeycodeTranslator.toChar(evt.keyCode); - if (key === 'up') { - increment = 1; - } else if (key === 'down') { - increment = -1; - } - - if (evt.shiftKey) { - increment = increment * 5; - } - - return increment; - }; - - ns.HslRgbColorPicker.prototype.updateColor_ = function (inputValue, model, dimension) { - var value = this.toModelValue_(inputValue, model, dimension); - if (model === 'hsv' || model === 'rgb') { - if (!isNaN(value)) { - var color = this.getColor_(model); - color[dimension] = this.normalizeDimension_(value, dimension); - this.setColor(color); - } - } else if (model === 'hex') { - if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) { - this.setColor(value); - } - } - }; - - ns.HslRgbColorPicker.prototype.onBlur_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - target.value = this.toInputValue_(model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - this.rgbColor = this.tinyColor.toRgb(); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.colorUpdatedCallback(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.HslRgbColorPicker.prototype.updateInputs = function () { - var inputs = this.container.querySelectorAll('input'); - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - var value = this.toInputValue_(model, dimension); - if (input.value != value) { - input.value = value; - } - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.HslRgbColorPicker.prototype.toInputValue_ = function (model, dimension) { - var value; - - if (model === 'rgb' || model === 'hsv') { - var color = this.getColor_(model); - value = color[dimension]; - - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - value = Math.round(value); - } else if (model === 'hex') { - value = this.tinyColor.toHexString(true); - } - - return value; - }; - - ns.HslRgbColorPicker.prototype.toModelValue_ = function (value, model, dimension) { - var modelValue; - - if (model === 'rgb' || model === 'hsv') { - modelValue = parseInt(value, 10); - if (dimension === 'v' || dimension === 's') { - modelValue = modelValue/100; - } - } else if (model === 'hex') { - modelValue = value; - } - - return modelValue; - }; - - ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { - var isTinyColor = typeof color == 'object' && color.hasOwnProperty('_tc_id'); - if (isTinyColor) { - return color; - } else { - return window.tinycolor(pskl.utils.copy(color)); - } - }; - - ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : this.normalizeDimension_(color.h, 'h'), - s : this.normalizeDimension_(color.s, 's'), - v : this.normalizeDimension_(color.v, 'v') - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) { - var range = this.getDimensionRange_(dimension); - return Math.max(range[0], Math.min(range[1], value)); - }; - - /** - * Update background colors for range inputs - */ - ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - var colors = this.getSliderBackgroundColors_(model, dimension); - slider.style.backgroundImage = "linear-gradient(to right, " + colors.start + " 0, " + colors.end + " 100%)"; - } - }; - - ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) { - var color = this.getColor_(model); - var start = pskl.utils.copy(color); - var end = pskl.utils.copy(color); - - var range = this.getDimensionRange_(dimension); - start[dimension] = range[0]; - end[dimension] = range[1]; - - return { - start : window.tinycolor(start).toRgbString(), - end : window.tinycolor(end).toRgbString() - }; - }; - - ns.HslRgbColorPicker.prototype.getDimensionRange_ = function (d) { - if (d === 'h') { - return [0, 359]; - } else if (d === 's' || d === 'v') { - return [0, 1]; - } else if (d === 'r' || d === 'g' || d === 'b') { - return [0, 255]; - } - }; - - ns.HslRgbColorPicker.prototype.getColor_ = function (model) { - var color; - if (model === 'hsv') { - color = this.hsvColor; - } else if (model === 'rgb'){ - color = this.rgbColor; - } - return color; - }; - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var data = { - framesheet : this.piskelController.serialize(), - fps : this.piskelController.getFPS(), - name : descriptor.name, - description : descriptor.description, - frames : this.piskelController.getFrameCount(), - first_frame_as_png : pskl.app.getFirstFrameAsPng(), - framesheet_as_png : pskl.app.getFramesheetAsPng() - }; - - if (descriptor.isPublic) { - data['public'] = true; - } - - var success = function () { - callbacks.success(); - callbacks.after(); - }; - - var error = function (response) { - callbacks.error(response.status); - callbacks.after(); - }; - - pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - // 1 minute = 1000 * 60 - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - this.savePiskel_('prev', previousPiskel, previousInfo); - } - - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - this.savePiskel_('next', this.piskelController.serialize(), JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(previousInfo.fps); - }); - }; - - ns.BackupService.prototype.savePiskel_ = function (type, piskel, info) { - try { - window.localStorage.setItem('bkp.' + type +'.piskel', piskel); - window.localStorage.setItem('bkp.' + type +'.info', info); - } catch (e) { - console.error('Could not save piskel backup in localStorage.', e); - } - }; -})(); - - - - -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.HistoryService = function (piskelController, shortcutService, deserializer) { - this.piskelController = piskelController || pskl.app.piskelController; - this.shortcutService = shortcutService || pskl.app.shortcutService; - this.deserializer = deserializer || pskl.utils.serialization.Deserializer; - - this.stateQueue = []; - this.currentIndex = -1; - - this.lastLoadState = -1; - - this.saveNextAsSnapshot = false; - }; - - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - ns.HistoryService.REPLAY = 'REPLAY'; - ns.HistoryService.SNAPSHOT_PERIOD = 50; - ns.HistoryService.LOAD_STATE_INTERVAL = 50; - /** - * This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command. - * Don't store snapshots for such events. - */ - ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT'; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); - - this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, stateInfo) { - this.saveState(stateInfo); - }; - - ns.HistoryService.prototype.saveState = function (stateInfo) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : stateInfo, - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT; - var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot; - if (isNoSnapshot && isAtAutoSnapshotInterval) { - this.saveNextAsSnapshot = true; - } else if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - this.saveNextAsSnapshot = false; - } - - this.stateQueue.push(state); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - // Should only do this when going backwards - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service.color'); - - var LOW_SAT = 0.1; - var LOW_LUM = 0.1; - var HI_LUM = 0.9; - - - var HUE_STEP = 36; - var HUE_BAGS = 10; - var HUE_BOUNDS = []; - for (var i = 0 ; i < HUE_BAGS ; i++) { - HUE_BOUNDS.push(i * HUE_STEP); - } - - ns.ColorSorter = function () { - this.colorsHslMap_ = {}; - }; - - ns.ColorSorter.prototype.sort = function (colors) { - this.colorsHslMap_ = {}; - - colors.forEach(function (color) { - this.colorsHslMap_[color] = window.tinycolor(color).toHsl(); - }.bind(this)); - - // sort by most frequent color - var darkColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l <= LOW_LUM; - }.bind(this)); - - var brightColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l >= HI_LUM; - }.bind(this)); - - var desaturatedColors = colors.filter(function (c) { - return brightColors.indexOf(c) === -1 && darkColors.indexOf(c) === -1; - }).filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.s <= LOW_SAT; - }.bind(this)); - - darkColors = this.sortOnHslProperty_(darkColors, 'l'); - brightColors = this.sortOnHslProperty_(brightColors, 'l'); - desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); - - var sortedColors = darkColors.concat(brightColors, desaturatedColors); - - var regularColors = colors.filter(function (c) { - return sortedColors.indexOf(c) === -1; - }); - - var regularColorsBags = HUE_BOUNDS.map(function (hue) { - var bagColors = regularColors.filter(function (color) { - var hsl = this.colorsHslMap_[color]; - return (hsl.h >= hue && hsl.h < hue + HUE_STEP); - }.bind(this)); - - return this.sortRegularColors_(bagColors); - }.bind(this)); - - return Array.prototype.concat.apply(sortedColors, regularColorsBags); - }; - - ns.ColorSorter.prototype.sortRegularColors_ = function (colors) { - var sortedColors = colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - var hDiff = Math.abs(hsl1.h - hsl2.h); - var sDiff = Math.abs(hsl1.s - hsl2.s); - var lDiff = Math.abs(hsl1.l - hsl2.l); - if (hDiff < 10) { - if (sDiff > lDiff) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - return this.compareValues_(hsl1.l, hsl2.l); - } - } else { - return this.compareValues_(hsl1.h, hsl2.h); - } - }.bind(this)); - - return sortedColors; - }; - - ns.ColorSorter.prototype.sortOnHslProperty_ = function (colors, property) { - return colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - return this.compareValues_(hsl1[property], hsl2[property]); - }.bind(this)); - }; - - ns.ColorSorter.prototype.compareValues_ = function (v1, v2) { - if (v1 > v2) { - return 1; - } else if (v1 < v2) { - return -1; - } - return 0; - }; - -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.CurrentColorsPalette = function () { - this.name = 'Current colors'; - this.id = Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsPalette.prototype.getColors = function () { - return pskl.app.currentColorsService.getCurrentColors(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteService = function () { - this.dynamicPalettes = []; - this.localStorageService = window.localStorage; - }; - - ns.PaletteService.prototype.getPalettes = function () { - var palettesString = this.localStorageService.getItem('piskel.palettes'); - var palettes = JSON.parse(palettesString) || []; - palettes = palettes.map(function (palette) { - return pskl.model.Palette.fromObject(palette); - }); - - return this.dynamicPalettes.concat(palettes); - }; - - ns.PaletteService.prototype.getPaletteById = function (paletteId) { - var palettes = this.getPalettes(); - return this.findPaletteInArray_(paletteId, palettes); - }; - - ns.PaletteService.prototype.savePalette = function (palette) { - var palettes = this.getPalettes(); - var existingPalette = this.findPaletteInArray_(palette.id, palettes); - if (existingPalette) { - var currentIndex = palettes.indexOf(existingPalette); - palettes.splice(currentIndex, 1, palette); - } else { - palettes.push(palette); - } - - this.savePalettes_(palettes); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteService.prototype.addDynamicPalette = function (palette) { - this.dynamicPalettes.push(palette); - }; - - ns.PaletteService.prototype.deletePaletteById = function (id) { - var palettes = this.getPalettes(); - var filteredPalettes = palettes.filter(function (palette) { - return palette.id !== id; - }); - - this.savePalettes_(filteredPalettes); - }; - - ns.PaletteService.prototype.savePalettes_ = function (palettes) { - palettes = palettes.filter(function (palette) { - return this.dynamicPalettes.indexOf(palette) === -1; - }.bind(this)); - this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteGplWriter = function (palette) { - this.palette = palette; - }; - - ns.PaletteGplWriter.prototype.write = function () { - var lines = []; - lines.push('GIMP Palette'); - lines.push('Name: ' + this.palette.name); - lines.push('Columns: 0'); - lines.push('#'); - this.palette.getColors().forEach(function (color) { - lines.push(this.writeColorLine(color)); - }.bind(this)); - lines.push('\r\n'); - - return lines.join('\r\n'); - }; - - ns.PaletteGplWriter.prototype.writeColorLine = function (color) { - var tinycolor = window.tinycolor(color); - var rgb = tinycolor.toRgb(); - var strBuffer = []; - strBuffer.push(this.padString(rgb.r, 3)); - strBuffer.push(this.padString(rgb.g, 3)); - strBuffer.push(this.padString(rgb.b, 3)); - strBuffer.push('Untitled'); - - return strBuffer.join(' '); - }; - - ns.PaletteGplWriter.prototype.padString = function (str, size) { - str = str.toString(); - var pad = (new Array(1+size-str.length)).join(' '); - return pad + str; - }; - -})(); -;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.AbstractPaletteFileReader = function (file, onSuccess, onError, colorLineRegexp) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - this.colorLineRegexp = colorLineRegexp; - }; - - ns.AbstractPaletteFileReader.prototype.extractColorFromLine = Constants.ABSTRACT_FUNCTION; - - ns.AbstractPaletteFileReader.prototype.read = function () { - pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this)); - }; - - ns.AbstractPaletteFileReader.prototype.onFileLoaded_ = function (content) { - var text = pskl.utils.Base64.toText(content); - var lines = text.match(/[^\r\n]+/g); - - var colorLines = lines.filter(function (l) { - return this.colorLineRegexp.test(l); - }.bind(this)); - - var colors = colorLines.map(this.extractColorFromLine.bind(this)); - - if (colors.length) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name, colors); - this.onSuccess(palette); - } else { - this.onError(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/; - var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; - - ns.PaletteGplReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteGplReader, ns.AbstractPaletteFileReader); - - ns.PaletteGplReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = window.tinycolor({ - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10) - }); - - return color.toRgbString(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.PaletteImageReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - - this.colorSorter_ = new pskl.service.color.ColorSorter(); - }; - - ns.PaletteImageReader.prototype.read = function () { - pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this)); - }; - - ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) { - var imageProcessor = new pskl.worker.ImageProcessor(image, - this.onWorkerSuccess_.bind(this), - this.onWorkerStep_.bind(this), - this.onWorkerError_.bind(this)); - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]); - - imageProcessor.process(); - }; - - ns.PaletteImageReader.prototype.onWorkerSuccess_ = function (event) { - var data = event.data; - var colorsMap = data.colorsMap; - - var colors = Object.keys(colorsMap); - - if (colors.length > 200) { - this.onError('Too many colors : ' + colors.length); - } else { - var uuid = pskl.utils.Uuid.generate(); - var sortedColors = this.colorSorter_.sort(colors); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', sortedColors); - - this.onSuccess(palette); - } - $.publish(Events.HIDE_PROGRESS); - }; - - ns.PaletteImageReader.prototype.onWorkerStep_ = function (event) { - var progress = event.data.progress; - $.publish(Events.UPDATE_PROGRESS, [{"progress": progress}]); - }; - - ns.PaletteImageReader.prototype.onWorkerError_ = function (event) { - $.publish(Events.HIDE_PROGRESS); - this.onError('Unable to process the image : ' + event.data.message); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})/; - - ns.PalettePalReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PalettePalReader, ns.AbstractPaletteFileReader); - - ns.PalettePalReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = 'rgb(' + matches[1] + ',' + matches[2] + ',' + matches[3] + ')'; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/; - - ns.PaletteTxtReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteTxtReader, ns.AbstractPaletteFileReader); - - ns.PaletteTxtReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = "#" + matches[1] + matches[2] + matches[3]; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var fileReaders = { - 'gpl' : ns.reader.PaletteGplReader, - 'pal' : ns.reader.PalettePalReader, - 'txt' : ns.reader.PaletteTxtReader, - 'img' : ns.reader.PaletteImageReader - }; - - ns.PaletteImportService = function () {}; - - ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader = this.getReader_(file, onSuccess, onError); - if (reader) { - reader.read(); - } else { - throw 'Could not find reader for file : ' + file.name; - } - }; - - ns.PaletteImportService.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.PaletteImportService.prototype.getReader_ = function (file, onSuccess, onError) { - var readerClass = this.getReaderClass_(file); - if (readerClass) { - return new readerClass(file, onSuccess, onError); - } else { - return null; - } - }; - - ns.PaletteImportService.prototype.getReaderClass_ = function (file) { - var readerClass; - if (this.isImage_(file)) { - readerClass = fileReaders.img; - } else { - var extension = this.getExtension_(file); - readerClass = fileReaders[extension]; - } - return readerClass; - }; - - ns.PaletteImportService.prototype.getExtension_ = function (file) { - var parts = file.name.split('.'); - var extension = parts[parts.length-1]; - return extension.toLowerCase(); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.addShortcuts = function (keys, callback) { - keys.forEach(function (key) { - this.addShortcut(key, callback); - }.bind(this)); - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+", - 188 : "<", - 190 : ">" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Create a Palette'), - this.toDescriptor_('</>', 'Select previous/next palette color'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} success success callback. 1st argument will be the uploaded image URL - * @param {Function} error error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, success, error) { - var data = { - data : imageData - }; - - var wrappedSuccess = function (response) { - success(Constants.IMAGE_SERVICE_GET_URL + response.responseText); - }; - - pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - this.currentColors = []; - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); - - this.colorSorter = new pskl.service.color.ColorSorter(); - this.paletteService = pskl.app.paletteService; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); - $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.setCurrentColors = function (colors) { - if (colors.join('') !== this.currentColors.join('')) { - this.currentColors = colors; - $.publish(Events.CURRENT_COLORS_UPDATED); - } - }; - - ns.CurrentColorsService.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.SELECTED_PALETTE) { - if (this.isCurrentColorsPaletteSelected_()) { - this.updateCurrentColors_(); - } - } - }; - - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { - if (this.isCurrentColorsPaletteSelected_()) { - this.updateCurrentColors_(); - } - }; - - ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); - - return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = true; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - var currentColors = this.colorSorter.sort(colorsArray); - - this.setCurrentColors(currentColors); - }; - - ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexString_(color); - frameColors[hexColor] = true; - }.bind(this)); - return frameColors; - }; - - ns.CurrentColorsService.prototype.toHexString_ = function (color) { - if (color === Constants.TRANSPARENT_COLOR) { - return color; - } else { - color = color.replace(/\s/g, ''); - var hexRe = (/^#([a-f0-9]{3}){1,2}$/i); - var rgbRe = (/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i); - if (hexRe.test(color)) { - return color.toUpperCase(); - } else if (rgbRe.test(color)) { - var exec = rgbRe.exec(color); - return pskl.utils.rgbToHex(exec[1] * 1, exec[2] * 1, exec[3] * 1); - } else { - console.error('Could not convert color to hex : ', color); - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - var isPiskel = /\.piskel$/i.test(file.name); - var isPalette = /\.(gpl|txt|pal)$/i.test(file.name); - if (isImage) { - this.readImageFile_(file); - } else if (isPiskel) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } else if (isPalette) { - pskl.app.paletteImportService.read(file, this.onPaletteLoaded_.bind(this)); - } - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.onPaletteLoaded_ = function (palette) { - pskl.app.paletteService.savePalette(palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.Tool = function () { - this.toolId = "tool"; - this.helpText = "Abstract tool"; - this.tooltipDescriptors = []; - }; - - ns.Tool.prototype.getHelpText = function() { - return this.helpText; - }; - - ns.Tool.prototype.getId = function() { - return this.toolId; - }; -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.IconMarkupRenderer = function () {}; - - ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) { - tooltipPosition = tooltipPosition || 'right'; - shortcut = shortcut ? '(' + shortcut + ')' : ''; - var tpl = pskl.utils.Template.get('drawingTool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : ['tool-icon', tool.toolId].join(' '), - toolid : tool.toolId, - title : this.getTooltipText(tool, shortcut), - tooltipposition : tooltipPosition - }); - }; - - ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) { - var descriptors = tool.tooltipDescriptors; - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : tool.getHelpText(), - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.IconMarkupRenderer.prototype.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.IconMarkupRenderer.prototype.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;/** - * @provide pskl.tools.drawing.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.BaseTool = function() { - pskl.tool.Tool.call(this); - this.toolId = "tool-base"; - }; - - pskl.utils.inherit(ns.BaseTool, pskl.tools.Tool); - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.tools.drawing'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [coords.col, coords.row]); - this.raiseSaveStateEvent({ - col : coords.col, - row : coords.row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.tools.drawing.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i 0) { - var node = this; - for (var i = 0 ; i < parts.length ; i++) { - if (!node[parts[i]]) { - node[parts[i]] = {}; - } - node = node[parts[i]]; - } - } - }); - var script = createNamespace + ""; - script = script.replace(/function \(\) \{/,"").replace(/\}[^}]*$/, ""); - script = "var name = '" + name + "';" + script; - - this.runScript(script); - }; - - ns.ImageProcessor.prototype.onWorkerMessage = function (event) { - if (event.data.type === 'STEP') { - this.onStep(event); - } else if (event.data.type === 'SUCCESS') { - this.onSuccess(event); - this.worker.terminate(); - } else if (event.data.type === 'ERROR') { - this.onError(event); - this.worker.terminate(); - } - }; - - ns.ImageProcessor.prototype.importAll__ = function (classToImport, classpath) { - this.createNamespace(classpath); - for (var key in classToImport) { - if (classToImport.hasOwnProperty(key)) { - this.addMethod(classToImport[key], classpath + '.' + key); - } - } - }; - - ns.ImageProcessor.prototype.addMethod__ = function (method, name) { - this.runScript(name + "=" + method); - }; - - ns.ImageProcessor.prototype.runScript__ = function (script) { - this.worker.postMessage({ - type : 'RUN_SCRIPT', - script : this.getScriptAsUrl(script) - }); - }; - - ns.ImageProcessor.prototype.getScriptAsUrl__ = function (script) { - var blob = new Blob([script], {type: "application/javascript"}); // pass a useful mime type here - return window.URL.createObjectURL(blob); - }; -})(); - - - -;/** - * @require Constants - * @require Events - */ -(function () { - var ns = $.namespace("pskl"); - /** - * Main application controller - */ - ns.app = { - - init : function () { - /** - * When started from APP Engine, appEngineToken_ (Boolean) should be set on window.pskl - */ - this.isAppEngineVersion = !!pskl.appEngineToken_; - - this.shortcutService = new pskl.service.keyboard.ShortcutService(); - this.shortcutService.init(); - - var size = { - height : Constants.DEFAULT.HEIGHT, - width : Constants.DEFAULT.WIDTH - }; - - var descriptor = new pskl.model.piskel.Descriptor('New Piskel', ''); - var piskel = new pskl.model.Piskel(size.width, size.height, descriptor); - - var layer = new pskl.model.Layer("Layer 1"); - var frame = new pskl.model.Frame(size.width, size.height); - - layer.addFrame(frame); - piskel.addLayer(layer); - - this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel); - this.corePiskelController.init(); - - this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); - this.piskelController.init(); - - this.paletteImportService = new pskl.service.palette.PaletteImportService(); - this.paletteService = new pskl.service.palette.PaletteService(); - this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette()); - - this.paletteController = new pskl.controller.PaletteController(); - this.paletteController.init(); - - this.currentColorsService = new pskl.service.CurrentColorsService(this.piskelController); - this.currentColorsService.init(); - - this.palettesListController = new pskl.controller.PalettesListController(this.paletteController, this.currentColorsService); - this.palettesListController.init(); - - this.cursorCoordinatesController = new pskl.controller.CursorCoordinatesController(this.piskelController); - this.cursorCoordinatesController.init(); - - this.drawingController = new pskl.controller.DrawingController(this.piskelController, this.paletteController, $('#drawing-canvas-container')); - this.drawingController.init(); - - this.animationController = new pskl.controller.AnimatedPreviewController(this.piskelController, $('#animated-preview-canvas-container')); - this.animationController.init(); - - this.minimapController = new pskl.controller.MinimapController(this.piskelController, this.animationController, this.drawingController, $('.minimap-container')); - this.minimapController.init(); - - this.previewFilmController = new pskl.controller.PreviewFilmController(this.piskelController, $('#preview-list')); - this.previewFilmController.init(); - - this.layersListController = new pskl.controller.LayersListController(this.piskelController); - this.layersListController.init(); - - this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController); - this.settingsController.init(); - - this.dialogsController = new pskl.controller.dialogs.DialogsController(this.piskelController); - this.dialogsController.init(); - - this.toolController = new pskl.controller.ToolController(); - this.toolController.init(); - - this.selectionManager = new pskl.selection.SelectionManager(this.piskelController); - this.selectionManager.init(); - - this.historyService = new pskl.service.HistoryService(this.corePiskelController); - this.historyService.init(); - - this.notificationController = new pskl.controller.NotificationController(); - this.notificationController.init(); - - this.transformationsController = new pskl.controller.TransformationsController(); - this.transformationsController.init(); - - this.progressBarController = new pskl.controller.ProgressBarController(); - this.progressBarController.init(); - - this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController(); - this.canvasBackgroundController.init(); - - this.localStorageService = new pskl.service.LocalStorageService(this.piskelController); - this.localStorageService.init(); - - this.imageUploadService = new pskl.service.ImageUploadService(); - this.imageUploadService.init(); - - this.cheatsheetService = new pskl.service.keyboard.CheatsheetService(); - this.cheatsheetService.init(); - - this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController); - this.savedStatusService.init(); - - this.backupService = new pskl.service.BackupService(this.piskelController); - this.backupService.init(); - - this.beforeUnloadService = new pskl.service.BeforeUnloadService(this.piskelController); - this.beforeUnloadService.init(); - - this.fileDropperService = new pskl.service.FileDropperService(this.piskelController, $('#drawing-canvas-container').get(0)); - this.fileDropperService.init(); - - if (this.isAppEngineVersion) { - this.storageService = new pskl.service.AppEngineStorageService(this.piskelController); - } else { - this.storageService = new pskl.service.GithubStorageService(this.piskelController); - } - this.storageService.init(); - - var drawingLoop = new pskl.rendering.DrawingLoop(); - drawingLoop.addCallback(this.render, this); - drawingLoop.start(); - - this.initTooltips_(); - - var piskelData = this.getPiskelInitData_(); - if (piskelData && piskelData.piskel) { - this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); - } - - if (pskl.devtools) { - pskl.devtools.init(); - } - }, - - loadPiskel_ : function (serializedPiskel, descriptor, fps) { - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - }, - - getPiskelInitData_ : function () { - return pskl.appEnginePiskelData_; - }, - - isLoggedIn : function () { - var piskelData = this.getPiskelInitData_(); - return piskelData && piskelData.isLoggedIn; - }, - - initTooltips_ : function () { - $('body').tooltip({ - selector: '[rel=tooltip]' - }); - }, - - render : function (delta) { - this.drawingController.render(delta); - this.animationController.render(delta); - this.previewFilmController.render(delta); - }, - - getFirstFrameAsPng : function () { - var firstFrame = this.piskelController.getFrameAt(0); - var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); - canvasRenderer.drawTransparentAs('rgba(0,0,0,0)'); - var firstFrameCanvas = canvasRenderer.render(); - return firstFrameCanvas.toDataURL("image/png"); - }, - - getFramesheetAsPng : function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - var framesheetCanvas = renderer.renderAsCanvas(); - return framesheetCanvas.toDataURL("image/png"); - } - }; -})(); - -;(function () { - var flipFrame = function (frame, horizontal, vertical) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - clone.forEachPixel(function (color, x, y) { - if (horizontal) { - x = w-x-1; - } - if (vertical) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - }; - - window.flip = function (horizontal, vertical) { - var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex(); - var layers = pskl.app.piskelController.getLayers(); - layers.forEach(function (layer) { - flipFrame(layer.getFrameAt(currentFrameIndex), horizontal, vertical); - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - window.copyToAll = function () { - var ref = pskl.app.piskelController.getCurrentFrame(); - var layer = pskl.app.piskelController.getCurrentLayer(); - layer.getFrames().forEach(function (frame) { - if (frame !== ref) { - frame.setPixels(ref.getPixels()); - } - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; -})(); \ No newline at end of file diff --git a/js/piskel-packaged-2015-03-02-09-38.js b/js/piskel-packaged-2015-03-02-09-38.js deleted file mode 100644 index 9391dab2..00000000 --- a/js/piskel-packaged-2015-03-02-09-38.js +++ /dev/null @@ -1,24855 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing', - - // SERVICE URLS - APPENGINE_SAVE_URL : 'save', - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - SELECT_TOOL : "SELECT_TOOL", - - TOOL_RELEASED : "TOOL_RELEASED", - TOOL_PRESSED : "TOOL_PRESSED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - HISTORY_STATE_SAVED: "HISTORY_STATE_SAVED", - HISTORY_STATE_LOADED: "HISTORY_STATE_LOADED", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - SHOW_PROGRESS: "SHOW_PROGRESS", - UPDATE_PROGRESS: "UPDATE_PROGRESS", - HIDE_PROGRESS: "HIDE_PROGRESS", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", - - MOUSE_EVENT : "MOUSE_EVENT", - - // Tests - TEST_RECORD_END : "TEST_RECORD_END", - TEST_CASE_END : "TEST_CASE_END", - TEST_SUITE_END : "TEST_SUITE_END" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i": ">", - '"': '"', - "'": ''', - "/": '/' - }; - ns.escapeHtml= function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml= function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], "g"); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Array = { - find : function (array, filterFn) { - var match = null; - array = Array.isArray(array) ? array : []; - var filtered = array.filter(filterFn); - if (filtered.length) { - match = filtered[0]; - } - return match; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/,'')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement('canvas'); - canvas.setAttribute('width', width); - canvas.setAttribute('height', height); - - if (typeof classList == 'string') { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.utils.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.utils.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, false); - }, - - enableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, true); - }, - - setImageSmoothing : function (canvas, smoothing) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = smoothing; - context.mozImageSmoothingEnabled = smoothing; - context.oImageSmoothingEnabled = smoothing; - context.webkitImageSmoothingEnabled = smoothing; - context.msImageSmoothingEnabled = smoothing; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.utils.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || 'png'; - var data = canvas.toDataURL('image/' + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Event = {}; - - ns.Event.addEventListener = function (el, type, callback, scope, args) { - if (typeof el === 'string') { - el = document.querySelector(el); - } - - var listener = { - el : el, - type : type, - callback : callback, - handler : args ? callback.bind(scope, args) : callback.bind(scope) - }; - - scope.__pskl_listeners = scope.__pskl_listeners || []; - scope.__pskl_listeners.push(listener); - el.addEventListener(type, listener.handler); - }; - - ns.Event.removeEventListener = function (el, type, callback, scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - if (listener.callback === callback && listener.el === el && listener.type === type) { - el.removeEventListener(type, listeners[i].handler); - listeners.splice(i, 1); - break; - } - } - } - }; - - ns.Event.removeAllEventListeners = function (scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - listener.el.removeEventListener(listener.type, listener.handler); - } - scope.__pskl_listeners = []; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.FrameTransform = { - VERTICAL : 'vertical', - HORIZONTAL : 'HORIZONTAL', - flip : function (frame, axis) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - clone.forEachPixel(function (color, x, y) { - if (axis === ns.FrameTransform.VERTICAL) { - x = w-x-1; - } else if (axis === ns.FrameTransform.HORIZONTAL) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - return frame; - }, - - CLOCKWISE : 'clockwise', - COUNTERCLOCKWISE : 'counterclockwise', - rotate : function (frame, direction) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - var max = Math.max(w, h); - var xDelta = Math.ceil((max - w)/2); - var yDelta = Math.ceil((max - h)/2); - - frame.forEachPixel(function (color, x, y) { - var _x = x, _y = y; - - // Convert to square coords - x = x + xDelta; - y = y + yDelta; - - // Perform the rotation - var tmpX = x, tmpY = y; - if (direction === ns.FrameTransform.CLOCKWISE) { - x = tmpY; - y = max - 1 - tmpX; - } else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) { - y = tmpX; - x = max - 1 - tmpY; - } - - // Convert the coordinates back to the rectangular grid - x = x - xDelta; - y = y - yDelta; - if (clone.containsPixel(x, y)) { - frame.pixels[_x][_y] = clone.getPixel(x, y); - } else { - frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR; - } - }); - frame.version++; - return frame; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - /** - * Render a Frame object as an image. - * Can optionally scale it (zoom) - * @param {Frame} frame - * @param {Number} zoom - * @return {Image} - */ - toImage : function (frame, zoom) { - zoom = zoom || 1; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }, - - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (color, col, row) { - if (color != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, color); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.utils.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); - }, - - createFromImageData_ : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels__ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba__ : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createLayerFromSpritesheet : function (image, frameCount) { - var width = image.width, - height = image.height, - frameWidth = width / frameCount; - - var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, height); - var context = canvas.getContext('2d'); - - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - context.clearRect(0, 0 , frameWidth, height); - context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); - var frame = pskl.utils.FrameUtils.createFromImage(canvas); - frames.push(frame); - } - return frames; - }, - - mergeLayers : function (layerA, layerB) { - var framesA = layerA.getFrames(); - var framesB = layerB.getFrames(); - var mergedFrames = []; - framesA.forEach(function (frame, index) { - var otherFrame = framesB[index]; - mergedFrames.push(pskl.utils.FrameUtils.merge([otherFrame, frame])); - }); - var mergedLayer = pskl.model.Layer.fromFrames(layerA.getName(), mergedFrames); - return mergedLayer; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.utils.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.utils.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.utils.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.utils.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.TooltipFormatter = {}; - - - ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) { - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : helpText, - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - MAX_FPS : 'MAX_FPS', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'MAX_FPS' : 24, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function(){ - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var workers = {}; - - ns.WorkerUtils = { - createWorker : function (worker, workerId) { - if (!workers[workerId]) { - var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")]; - var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here - workers[workerId] = window.URL.createObjectURL(blob); - } - - return new Worker(workers[workerId]); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function (){}; - error = error || function (){}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function(e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function(e) { - error(e, this); - }; - - return xhr; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var step_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - step_callback = callback.step; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - if (!flat) { - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - } - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.size() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.size = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels())); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Palette = function (id, name, colors) { - this.id = id; - this.name = name; - this.colors = colors; - }; - - ns.Palette.fromObject = function (paletteObj) { - var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); - return new ns.Palette(paletteObj.id, paletteObj.name, colors); - }; - - ns.Palette.prototype.getColors = function () { - return this.colors; - }; - - ns.Palette.prototype.setColors = function (colors) { - this.colors = colors; - }; - - ns.Palette.prototype.get = function (index) { - return this.colors[index]; - }; - - ns.Palette.prototype.set = function (index, color) { - this.colors[index] = color; - }; - - ns.Palette.prototype.add = function (color) { - this.colors.push(color); - }; - - ns.Palette.prototype.size = function () { - return this.colors.length; - }; - - ns.Palette.prototype.removeAt = function (index) { - this.colors.splice(index, 1); - }; - - ns.Palette.prototype.move = function (oldIndex, newIndex) { - this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].size() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.addLayerAt = function (layer, index) { - this.layers.splice(index, 0, layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classList - */ - ns.FrameRenderer = function (container, renderingOptions, classList) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classList = classList || []; - this.classList.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.utils.CanvasUtils.clear(this.canvas); - pskl.utils.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.utils.CanvasUtils.createCanvas(width, height, this.classList); - pskl.utils.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) { - var cellSize = this.zoom; - - x = x * cellSize; - y = y * cellSize; - - x = x - this.offset.x * cellSize; - y = y - this.offset.y * cellSize; - - x = x + this.margin.x; - y = y + this.margin.y; - - var containerOffset = this.container.offset(); - x = x + containerOffset.left; - y = y + containerOffset.top; - - return { - x : x + (cellSize/2), - y : y + (cellSize/2) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - var w = 1; - while (color === frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width || this.canvas.height*this.zoom < this.displayCanvas.height) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, width); - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (renderer, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - this.renderer = renderer; - this.add(this.renderer); - - this.hash = ''; - }; - - ns.OnionSkinRenderer.createInContainer = function (container, renderingOptions, piskelController) { - // Do not use CachedFrameRenderers here, caching is performed in the render method - var renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ['onion-skin-canvas']); - return new ns.OnionSkinRenderer(renderer, piskelController); - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var frames = this.getOnionFrames_(); - var hash = this.computeHash_(frames); - if (this.hash != hash) { - this.hash = hash; - this.clear(); - if (frames.length > 0) { - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.getOnionFrames_ = function () { - var frames = []; - - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var layer = this.piskelController.getCurrentLayer(); - - var previousIndex = currentFrameIndex - 1; - var previousFrame = layer.getFrameAt(previousIndex); - if (previousFrame) { - frames.push(previousFrame); - } - - var nextIndex = currentFrameIndex + 1; - var nextFrame = layer.getFrameAt(nextIndex); - if (nextFrame) { - frames.push(nextFrame); - } - - return frames; - }; - - ns.OnionSkinRenderer.prototype.computeHash_ = function (frames) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - return [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join('-'); - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.hash = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - var containerEl = container.get(0); - var containerDocument = containerEl.ownerDocument; - this.displayContainer = containerDocument.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classList) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classList); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - - for(var x = 0, width = this.frame.getWidth(); x < width; x++) { - for(var y = 0, height = this.frame.getHeight(); y < height; y++) { - var color = this.frame.getPixel(x, y); - var w = 1; - while (color === this.frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.utils.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, width); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * previewController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.previewController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.size(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.mergeDownLayerAt = function (index) { - var layer = this.getLayerByIndex(index); - var downLayer = this.getLayerByIndex(index-1); - if (layer && downLayer) { - var mergedLayer = pskl.utils.LayerUtils.mergeLayers(layer, downLayer); - this.removeLayerAt(index); - this.piskel.addLayerAt(mergedLayer, index); - this.removeLayerAt(index-1); - this.selectLayer(mergedLayer); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.removeLayerAt(currentLayerIndex); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - // DECORATED WITH RESET - this.resetWrap_('setCurrentFrameIndex'); - this.resetWrap_('selectNextFrame'); - this.resetWrap_('selectPreviousFrame'); - this.resetWrap_('setCurrentLayerIndex'); - this.resetWrap_('selectLayer'); - // DECORATED WITH SAVE, NO RESET - this.saveWrap_('renameLayerAt', false); - // DECORATED WITH SAVE, WITH RESET - this.saveWrap_('removeCurrentLayer', true); - this.saveWrap_('addFrame', true); - this.saveWrap_('addFrameAtCurrentIndex', true); - this.saveWrap_('addFrameAt', true); - this.saveWrap_('removeFrameAt', true); - this.saveWrap_('duplicateCurrentFrame', true); - this.saveWrap_('duplicateFrameAt', true); - this.saveWrap_('moveFrame', true); - this.saveWrap_('createLayer', true); - this.saveWrap_('mergeDownLayerAt', true); - this.saveWrap_('moveLayerUp', true); - this.saveWrap_('moveLayerDown', true); - this.saveWrap_('removeCurrentLayer', true); - - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.resetWrap_ = function (methodName) { - this[methodName] = function () { - this.piskelController[methodName].apply(this.piskelController, arguments); - $.publish(Events.PISKEL_RESET); - }; - }; - - ns.PublicPiskelController.prototype.saveWrap_ = function (methodName, reset) { - this[methodName] = reset ? function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - $.publish(Events.PISKEL_RESET); - } : function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - }; - }; - - ns.PublicPiskelController.prototype.getStateInfo_ = function () { - var stateInfo = { - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - return stateInfo; - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args, stateInfo) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : { - fn : fn, - args : args - }, - state : stateInfo - }); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - this.dragHandler = new ns.drawing.DragHandler(this); - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = pskl.rendering.OnionSkinRenderer.createInContainer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChange_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(function () { - this.afterWindowResize_(); - this.resetZoom_(); - }.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isIE11) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChange_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - $.publish(Events.MOUSE_EVENT, [event, this]); - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - - this.isClicked = true; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - this.dragHandler.startDrag(event.clientX, event.clientY); - } else { - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - $.publish(Events.TOOL_PRESSED); - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.getSpriteCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - if(this.currentMouseButton_ == Constants.MIDDLE_BUTTON) { - this.dragHandler.updateDrag(x, y); - } else { - $.publish(Events.MOUSE_EVENT, [event, this]); - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - } else { - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - // Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40 - var delta; - if (pskl.utils.UserAgent.isChrome) { - delta = event.wheelDeltaY; - } else if (pskl.utils.UserAgent.isIE11) { - delta = event.wheelDelta; - } else if (pskl.utils.UserAgent.isFirefox) { - delta = -40 * event.deltaY; - } - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - if(this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (this.dragHandler.isDragging()) { - this.dragHandler.stopDrag(); - } else if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) { - return this.renderer.reverseCoordinates(spriteX, spriteY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.getAvailableHeight_(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.getAvailableWidth_(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.getOffset = function () { - return this.compositeRenderer.getOffset(); - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.drawing'); - - /** - * Multiplier applied between the mouse movement and viewport movement - * @type {Number} - */ - var MULTIPLIER = 2; - - /** - * Dedicated handler to drag the drawing canvas using the mouse - * Will store the initial coordinates as well as the status of the drag - * @param {DrawingController} drawingController - */ - ns.DragHandler = function (drawingController) { - this.drawingController = drawingController; - - this.isDragging_ = false; - this.updateOrigin_(-1, -1); - }; - - /** - * Initialize a drag session. - * @param {Number} x : x coordinate of the mouse event that initiated the drag - * @param {Number} y : y coordinate of the mouse event that initiated the drag - */ - ns.DragHandler.prototype.startDrag = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - }; - - /** - * Update the drag status - * @param {Number} x : x coordinate of the mouse event that triggered the update - * @param {Number} y : y coordinate of the mouse event that triggered the update - */ - ns.DragHandler.prototype.updateDrag = function (x, y) { - var currentOffset = this.drawingController.getOffset(); - var offset = this.calculateOffset_(x, y); - if (currentOffset.y !== offset.y || currentOffset.x !== offset.x) { - this.isDragging_ = true; - this.drawingController.setOffset(offset.x, offset.y); - - // retrieve the updated coordinates after moving the sprite - // and store them as the new drag origin - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - } - }; - - /** - * Stop the drag session - */ - ns.DragHandler.prototype.stopDrag = function () { - this.isDragging_ = false; - this.origin = null; - }; - - /** - * Will return true if the drag handler effectively MOVED the offset - * during the current drag session - */ - ns.DragHandler.prototype.isDragging = function () { - return this.isDragging_; - }; - - ns.DragHandler.prototype.calculateOffset_ = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - var currentOffset = this.drawingController.getOffset(); - - var offset = { - x : currentOffset.x - MULTIPLIER * (coords.x - this.origin.x), - y : currentOffset.y - MULTIPLIER * (coords.y - this.origin.y) - }; - - return offset; - }; - - ns.DragHandler.prototype.updateOrigin_ = function (x, y) { - this.origin = this.origin || {}; - this.origin.x = x; - this.origin.y = y; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.FramesListController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.FramesListController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.FramesListController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.FramesListController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.FramesListController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.FramesListController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.FramesListController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.FramesListController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.FramesListController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.FramesListController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.FramesListController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - var height = this.zoom * this.piskelController.getCurrentFrame().getHeight(); - var horizontalMargin = (Constants.PREVIEW_FILM_SIZE - height) / 2; - canvasContainer.style.marginTop = horizontalMargin + 'px'; - - var width = this.zoom * this.piskelController.getCurrentFrame().getWidth(); - var verticalMargin = (Constants.PREVIEW_FILM_SIZE - width) / 2; - canvasContainer.style.marginLeft = verticalMargin + 'px'; - canvasContainer.style.marginRight = verticalMargin + 'px'; - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.FramesListController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.FramesListController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.FramesListController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.utils.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.FramesListController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var frameSize = Math.max(frame.getHeight(), frame.getWidth()); - - return Constants.PREVIEW_FILM_SIZE/frameSize; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - this.updateButtonStatus_(); - }; - - ns.LayersListController.prototype.updateButtonStatus_ = function () { - var layers = this.piskelController.getLayers(); - var currentLayer = this.piskelController.getCurrentLayer(); - var index = this.piskelController.getCurrentLayerIndex(); - - var isLast = index === 0; - var isOnly = layers.length === 1; - var isFirst = index === layers.length - 1; - - this.toggleButtonDisabledState_('up', isFirst); - this.toggleButtonDisabledState_('down', isLast); - this.toggleButtonDisabledState_('merge', isLast); - this.toggleButtonDisabledState_('delete', isOnly); - }; - - ns.LayersListController.prototype.toggleButtonDisabledState_ = function (buttonAction, isDisabled) { - var button = document.querySelector('.layers-button[data-action="'+buttonAction+'"]'); - if (isDisabled) { - button.setAttribute('disabled', 'disabled'); - } else { - button.removeAttribute('disabled'); - } - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } - }; - - ns.LayersListController.prototype.renameCurrentLayer_ = function () { - var layer = this.piskelController.getCurrentLayer(); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.mergeDownCurrentLayer_ = function () { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.mergeDownLayerAt(index); - this.renderLayerList_(); - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } else if (action == 'merge') { - this.mergeDownCurrentLayer_(); - } else if (action == 'edit') { - this.renameCurrentLayer_(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - ns.PopupPreviewController = function (piskelController) { - this.piskelController = piskelController; - this.popup = null; - this.renderer = null; - this.renderFlag = false; - }; - - ns.PopupPreviewController.prototype.init = function () { - pskl.utils.Event.addEventListener(window, 'unload', this.onMainWindowUnload_, this); - }; - - ns.PopupPreviewController.prototype.isOpen = function () { - return !!this.popup; - }; - - ns.PopupPreviewController.prototype.open = function () { - if (!this.isOpen()) { - this.popup = window.open('/popup-preview.html', '', 'width=320,height=320'); - } - }; - - ns.PopupPreviewController.prototype.onPopupLoaded = function () { - pskl.utils.Event.addEventListener(this.popup, 'resize', this.onWindowResize_, this); - pskl.utils.Event.addEventListener(this.popup, 'unload', this.onPopupClosed_, this); - var container = this.popup.document.querySelector('.preview-container'); - this.renderer = new pskl.rendering.frame.TiledFrameRenderer($(container)); - this.updateZoom_(); - this.renderFlag = true; - }; - - - ns.PopupPreviewController.prototype.render = function (frame) { - if (this.isOpen() && this.renderer) { - this.renderer.render(frame); - this.renderFlag = false; - } - }; - - ns.PopupPreviewController.prototype.onWindowResize_ = function (frame) { - this.updateZoom_(); - this.renderFlag = true; - }; - - ns.PopupPreviewController.prototype.updateZoom_ = function () { - var documentElement = this.popup.document.documentElement; - var wZoom = documentElement.clientWidth / this.piskelController.getWidth(); - var hZoom = documentElement.clientHeight / this.piskelController.getHeight(); - var zoom = Math.min(wZoom, hZoom); - - this.renderer.setZoom(zoom); - - var height = this.piskelController.getHeight() * zoom; - var width = this.piskelController.getWidth() * zoom; - - var container = this.popup.document.querySelector('.preview-container'); - container.style.height = height + 'px'; - container.style.width = width + 'px'; - - var horizontalMargin = (documentElement.clientHeight - height) / 2; - container.style.marginTop = horizontalMargin + 'px'; - container.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (documentElement.clientWidth - width) / 2; - container.style.marginLeft = verticalMargin + 'px'; - container.style.marginRight = verticalMargin + 'px'; - }; - - ns.PopupPreviewController.prototype.onPopupClosed_ = function () { - var popup = this.popup; - console.log(popup); - this.popup = null; - }; - - ns.PopupPreviewController.prototype.onMainWindowUnload_ = function () { - if (this.isOpen()) { - this.popup.close(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.PreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.renderFlag = true; - - this.fpsRangeInput = $('#preview-fps'); - this.fpsCounterDisplay = $('#display-fps'); - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - this.popupPreviewController = new ns.PopupPreviewController(piskelController); - }; - - ns.PreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this)); - document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.utils.Event.addEventListener('.open-popup-preview-button', 'click', this.onOpenPopupPreviewClick_, this); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - $.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true)); - $.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true)); - - this.popupPreviewController.init(); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - this.updateMaxFPS_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.onOpenPopupPreviewClick_ = function () { - this.popupPreviewController.open(); - }; - - ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else if (name == pskl.UserSettings.MAX_FPS) { - this.updateMaxFPS_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.PreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.PreviewController.prototype.updateMaxFPS_ = function () { - var maxFps = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.fpsRangeInput.get(0).setAttribute('max', maxFps); - this.setFPS(Math.min(this.fps, maxFps)); - }; - - ns.PreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.PreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.PreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.PreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt(this.fpsRangeInput[0].value, 10)); - - }; - - ns.PreviewController.prototype.setFPS = function (fps) { - if (typeof fps === 'number') { - this.fps = fps; - // reset - this.fpsRangeInput.get(0).value = 0; - // set proper value - this.fpsRangeInput.get(0).value = this.fps; - this.fpsRangeInput.blur(); - this.fpsCounterDisplay.html(this.fps + ' FPS'); - } - }; - - ns.PreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.PreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = this.getNextIndex_(delta); - if (this.shoudlRender_() || this.currentIndex != index) { - this.currentIndex = index; - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - this.renderFlag = false; - - this.popupPreviewController.render(frame); - } - }; - - ns.PreviewController.prototype.getNextIndex_ = function (delta) { - if (this.fps === 0) { - return this.piskelController.getCurrentFrameIndex(); - } else { - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (!this.piskelController.hasFrameAt(index)) { - this.elapsedTime = 0; - index = 0; - } - return index; - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.PreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var hZoom = PREVIEW_SIZE / frame.getHeight(), - wZoom = PREVIEW_SIZE / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.PreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + 'px'; - containerEl.style.width = width + 'px'; - - var horizontalMargin = (PREVIEW_SIZE - height) / 2; - containerEl.style.marginTop = horizontalMargin + 'px'; - containerEl.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (PREVIEW_SIZE - width) / 2; - containerEl.style.marginLeft = verticalMargin + 'px'; - containerEl.style.marginRight = verticalMargin + 'px'; - }; - - ns.PreviewController.prototype.setRenderFlag_ = function (bool) { - this.renderFlag = bool; - }; - - ns.PreviewController.prototype.shoudlRender_ = function () { - return this.renderFlag || this.popupPreviewController.renderFlag; - }; - - ns.PreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, previewController, drawingController, container) { - this.piskelController = piskelController; - this.previewController = previewController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - this.isVisible = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.minimapEl = document.createElement('DIV'); - this.minimapEl.className = 'minimap-crop-frame'; - this.minimapEl.style.display = 'none'; - $(this.container).append(this.minimapEl); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var verticalRatio = this.getVerticalRatio_(); - var horizontalRatio = this.getHorizontalRatio_(); - if (verticalRatio > 1 || horizontalRatio > 1) { - this.displayMinimap_(); - } else { - this.hideMinimap_(); - } - }; - - ns.MinimapController.prototype.displayMinimap_ = function () { - var minimapSize = this.getMinimapSize_(); - var previewSize = this.getPreviewSize_(); - - var containerHeight = this.container.height(); - var containerWidth = this.container.width(); - - // offset(x, y) in frame pixels - var offset = this.drawingController.getRenderer().getOffset(); - - // the preview is centered in a square container - // if the sprite is not a square, a margin is needed on the appropriate coordinate - // before adding the offset coming from the drawing area - var leftMargin = (containerWidth - Math.max(minimapSize.width, previewSize.width))/2; - var leftOffset = offset.x * this.previewController.getZoom(); - var left = leftMargin + leftOffset; - - var topMargin = (containerHeight - Math.max(minimapSize.height, previewSize.height))/2; - var topOffset = offset.y * this.previewController.getZoom(); - var top = topMargin + topOffset; - - this.minimapEl.style.display = 'block'; - this.minimapEl.style.width = Math.min(minimapSize.width, containerWidth) + 'px'; - this.minimapEl.style.height = Math.min(minimapSize.height, containerHeight) + 'px'; - this.minimapEl.style.left = Math.max(0, left) + 'px'; - this.minimapEl.style.top = Math.max(0, top) + 'px'; - - this.isVisible = true; - }; - - ns.MinimapController.prototype.getMinimapSize_ = function () { - // Calculate the ratio to translate drawing area sizes to animated preview sizes - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var animatedPreviewZoom = this.previewController.getZoom(); - var ratio = drawingAreaZoom / animatedPreviewZoom; - - var displaySize = this.drawingController.getRenderer().getDisplaySize(); - var minimapWidth = displaySize.width / ratio; - var minimapHeight = displaySize.height / ratio; - - return { - width : minimapWidth, - height: minimapHeight - }; - }; - - ns.MinimapController.prototype.getPreviewSize_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewWidth = frame.getWidth() * this.previewController.getZoom(); - var previewHeight = frame.getHeight() * this.previewController.getZoom(); - - return { - width : previewWidth, - height: previewHeight - }; - }; - - ns.MinimapController.prototype.hideMinimap_ = function () { - this.minimapEl.style.display = 'none'; - this.isVisible = false; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isVisible && this.isClicked) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.previewController.getCoordinates(x, y); - - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / this.getHorizontalRatio_(); - var height = frameHeight / this.getVerticalRatio_(); - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getVerticalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalHeight = frame.getHeight() * drawingAreaZoom; - var frameDisplayHeight = this.drawingController.getRenderer().getDisplaySize().height; - - return frameTotalHeight / frameDisplayHeight; - }; - - ns.MinimapController.prototype.getHorizontalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalWidth = frame.getWidth() * drawingAreaZoom; - var frameDisplayWidth = this.drawingController.getRenderer().getDisplaySize().width; - - return frameTotalWidth / frameDisplayWidth; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()), - toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()), - toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()), - toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()), - toDescriptor('move', 'M', new pskl.tools.drawing.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - - $.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.tools.drawing.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) { - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - return pskl.utils.Array.find(this.tools, function (tool) { - return tool.instance.toolId == toolId; - }); - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var html = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - html += this.toolIconRenderer.render(tool.instance, tool.shortcut); - } - $('#tools-container').html(html); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteService = pskl.app.paletteService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - - var createPaletteButton_ = document.querySelector('.create-palette-button'); - var editPaletteButton_ = document.querySelector('.edit-palette-button'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - editPaletteButton_.addEventListener('click', this.onEditPaletteClick_.bind(this)); - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - - pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this)); - pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this)); - - this.fillPaletteList(); - this.updateFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = this.paletteService.getPalettes(); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.colorPaletteSelect_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - - var colors = this.getSelectedPaletteColors_(); - - if (colors.length > 0) { - var html = colors.map(function (color, index) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - } else { - this.colorListContainer_.innerHTML = pskl.utils.Template.get('palettes-list-no-colors-partial'); - } - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var palette = this.getSelectedPalette_(); - if (palette) { - colors = palette.getColors(); - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.getSelectedPalette_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - return this.paletteService.getPaletteById(paletteId); - }; - - ns.PalettesListController.prototype.selectNextColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() + 1); - }; - - ns.PalettesListController.prototype.selectPreviousColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() - 1); - }; - - ns.PalettesListController.prototype.getCurrentColorIndex_ = function () { - var currentIndex = 0; - var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME); - if (selectedColor) { - currentIndex = parseInt(selectedColor.dataset.colorIndex, 10); - } - return currentIndex; - }; - - ns.PalettesListController.prototype.selectColor_ = function (index) { - var colors = this.getSelectedPaletteColors_(); - var color = colors[index]; - if (color) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } - }; - - ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.SELECTED_PALETTE) { - this.updateFromUserSettings(); - } - }; - - ns.PalettesListController.prototype.updateFromUserSettings = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - this.fillColorListContainer(); - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - this.selectPalette(paletteId); - this.colorPaletteSelect_.blur(); - }; - - ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); - }; - - ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : paletteId - }); - }; - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.updateFromUserSettings(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.ProgressBarController = function () { - this.template = pskl.utils.Template.get('progress-bar-template'); - this.progressBar = null; - this.progressBarStatus = null; - - this.showProgressTimer_ = 0; - }; - - ns.ProgressBarController.prototype.init = function () { - $.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this)); - $.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this)); - $.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this)); - }; - - ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) { - this.removeProgressBar_(); - this.showProgressTimer_ = window.setTimeout(this.onTimerExpired_.bind(this, progressInfo), 300); - }; - - ns.ProgressBarController.prototype.onTimerExpired_ = function (progressInfo) { - var progressBarHtml = pskl.utils.Template.replace(this.template, { - name : progressInfo.name, - status : 0 - }); - - var progressBarEl = pskl.utils.Template.createFromHTML(progressBarHtml); - document.body.appendChild(progressBarEl); - - this.progressBar = document.querySelector('.progress-bar'); - this.progressBarStatus = document.querySelector('.progress-bar-status'); - }; - - ns.ProgressBarController.prototype.updateProgress_ = function (event, progressInfo) { - if (this.progressBar && this.progressBarStatus) { - var progress = progressInfo.progress; - var width = this.progressBar.offsetWidth; - var progressWidth = width - ((progress * width) / 100); - this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; - this.progressBarStatus.innerHTML = progress + '%'; - } - }; - - ns.ProgressBarController.prototype.hideProgress_ = function (event, progressInfo) { - if (this.showProgressTimer_) { - window.clearTimeout(this.showProgressTimer_); - } - this.removeProgressBar_(); - }; - - ns.ProgressBarController.prototype.removeProgressBar_ = function () { - var progressBarContainer = document.querySelector('.progress-bar-container'); - if (progressBarContainer) { - progressBarContainer.parentNode.removeChild(progressBarContainer); - this.progressBar = null; - this.progressBarStatus = null; - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - - message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this)); - if (messageInfo.behavior) { - messageInfo.behavior(message); - } - - if (messageInfo.hideDelay) { - window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.TransformationsController = function () { - - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('flip', '', new pskl.tools.transform.Flip()), - toDescriptor('rotate', '', new pskl.tools.transform.Rotate()), - toDescriptor('clone', '', new pskl.tools.transform.Clone()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - ns.TransformationsController.prototype.init = function () { - var container = document.querySelector('.transformations-container'); - this.toolsContainer = container.querySelector('.tools-wrapper'); - container.addEventListener('click', this.onTransformationClick.bind(this)); - this.createToolsDom_(); - }; - - - ns.TransformationsController.prototype.onTransformationClick = function (evt) { - var toolId = evt.target.dataset.toolId; - this.tools.forEach(function (tool) { - if (tool.instance.toolId === toolId) { - tool.instance.apply(evt); - } - }.bind(this)); - }; - - ns.TransformationsController.prototype.createToolsDom_ = function() { - var html = this.tools.reduce(function (p, tool) { - return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left'); - }.bind(this), ''); - this.toolsContainer.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - ns.AbstractSettingController = function () {}; - - ns.AbstractSettingController.prototype.addEventListener = function (el, type, callback) { - pskl.utils.Event.addEventListener(el, type, callback, this); - }; - - - ns.AbstractSettingController.prototype.destroy = function () { - pskl.utils.Event.removeAllEventListeners(this); - this.nullifyDomReferences_(); - }; - - ns.AbstractSettingController.prototype.nullifyDomReferences_ = function () { - for (var key in this) { - if (this.hasOwnProperty(key)) { - var isHTMLElement = this[key] && this[key].nodeName; - if (isHTMLElement) { - this[key] = null; - } - } - } - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - pskl.utils.inherit(ns.ApplicationSettingsController, pskl.controller.settings.AbstractSettingController); - - ns.ApplicationSettingsController.prototype.init = function() { - this.backgroundContainer = document.querySelector('.background-picker-wrapper'); - this.addEventListener(this.backgroundContainer, 'click', this.onBackgroundClick_); - - // Highlight selected background : - var background = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - var selectedBackground = this.backgroundContainer.querySelector('[data-background=' + background + ']'); - if (selectedBackground) { - selectedBackground.classList.add('selected'); - } - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - var gridSelect = document.querySelector('.grid-width-select'); - var selectedOption = gridSelect.querySelector('option[value="'+gridWidth+'"]'); - if (selectedOption) { - selectedOption.setAttribute('selected', 'selected'); - } - - this.addEventListener(gridSelect, 'change', this.onGridWidthChange_); - - // Tiled preview - var tiledPreview = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var tiledPreviewCheckbox = document.querySelector('.tiled-preview-checkbox'); - if (tiledPreview) { - tiledPreviewCheckbox.setAttribute('checked', tiledPreview); - } - this.addEventListener(tiledPreviewCheckbox, 'change', this.onTiledPreviewChange_); - - // Max FPS - var maxFpsInput = document.querySelector('.max-fps-input'); - maxFpsInput.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.addEventListener(maxFpsInput, 'change', this.onMaxFpsChange_); - - // Form - this.applicationSettingsForm = document.querySelector('[name="application-settings-form"]'); - this.addEventListener(this.applicationSettingsForm, 'submit', this.onFormSubmit_); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange_ = function (evt) { - var width = parseInt(evt.target.value, 10); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, width); - }; - - ns.ApplicationSettingsController.prototype.onTiledPreviewChange_ = function (evt) { - pskl.UserSettings.set(pskl.UserSettings.TILED_PREVIEW, evt.currentTarget.checked); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick_ = function (evt) { - var target = evt.target; - var background = target.dataset.background; - if (background) { - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, background); - var selected = this.backgroundContainer.querySelector('.selected'); - if (selected) { - selected.classList.remove('selected'); - } - target.classList.add('selected'); - } - }; - - ns.ApplicationSettingsController.prototype.onMaxFpsChange_ = function (evt) { - var target = evt.target; - var fps = parseInt(target.value, 10); - if (fps && !isNaN(fps)) { - pskl.UserSettings.set(pskl.UserSettings.MAX_FPS, fps); - } else { - target.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - } - }; - - ns.ApplicationSettingsController.prototype.onFormSubmit_ = function (evt) { - evt.preventDefault(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController); - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = document.querySelector(".gif-upload-button"); - this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_); - - this.downloadButton = document.querySelector(".gif-download-button"); - this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.uploadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.downloadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.downloadImageData_ = function (imageData) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.GifExportController.prototype.uploadImageData_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this), this.onImageUploadFailed_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.onImageUploadFailed_ = function (event, xhr) { - if (xhr.status === 500) { - $.publish(Events.SHOW_NOTIFICATION, [{ - "content": "Upload failed : " + xhr.responseText, - "hideDelay" : 5000 - }]); - } - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 5, - quality: 1, - width: this.piskelController.getWidth() * zoom, - height: this.piskelController.getHeight() * zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Building animated GIF ...'}]); - gif.on('progress', function(percentage) { - $.publish(Events.UPDATE_PROGRESS, [{"progress": (percentage*100).toFixed(1)}]); - }.bind(this)); - - gif.on('finished', function(blob) { - $.publish(Events.HIDE_PROGRESS); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController); - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelector('.png-export-preview'); - this.pngFilePrefixInput = document.getElementById('zip-prefix-name'); - this.pngFilePrefixInput.value = 'sprite_'; - - var downloadButton = document.querySelector(".png-download-button"); - this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_); - - var zipButton = document.querySelector(".zip-generate-button"); - this.addEventListener(zipButton, 'click', this.onZipButtonClick_); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var basename = this.pngFilePrefixInput.value; - var filename = basename + (i+1) + ".png"; - zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - var OPTION_CLASSNAME = 'resize-origin-option'; - - ns.AnchorWidget = function (container) { - this.container = container; - this.disabled = false; - pskl.utils.Event.addEventListener(this.container, 'click', this.onResizeOriginClick_, this); - }; - - ns.AnchorWidget.ORIGIN = { - TOPLEFT : 'TOPLEFT', - TOP : 'TOP', - TOPRIGHT : 'TOPRIGHT', - MIDDLELEFT : 'MIDDLELEFT', - MIDDLE : 'MIDDLE', - MIDDLERIGHT : 'MIDDLERIGHT', - BOTTOMLEFT : 'BOTTOMLEFT', - BOTTOM : 'BOTTOM', - BOTTOMRIGHT : 'BOTTOMRIGHT' - }; - - ns.AnchorWidget.prototype.destroy = function (evt) { - pskl.utils.Event.removeAllEventListeners(this); - this.container = null; - }; - - ns.AnchorWidget.prototype.onResizeOriginClick_ = function (evt) { - var origin = evt.target.dataset.origin; - if (origin && ns.AnchorWidget.ORIGIN[origin] && !this.disabled) { - this.setOrigin(origin); - } - }; - - ns.AnchorWidget.prototype.setOrigin = function (origin) { - this.origin = origin; - var previous = document.querySelector('.'+OPTION_CLASSNAME+'.selected'); - if (previous) { - previous.classList.remove('selected'); - } - - var selected = document.querySelector('.'+OPTION_CLASSNAME+'[data-origin="' + origin + '"]'); - if (selected) { - selected.classList.add('selected'); - this.refreshNeighbors_(selected); - } - }; - - ns.AnchorWidget.prototype.getOrigin = function () { - return this.origin; - }; - - ns.AnchorWidget.prototype.disable = function () { - this.disabled = true; - this.container.classList.add('transition'); - this.container.classList.add('disabled'); - }; - - ns.AnchorWidget.prototype.enable = function () { - this.disabled = false; - this.container.classList.remove('disabled'); - window.setTimeout(this.container.classList.remove.bind(this.container.classList, 'transition'), 250); - }; - - ns.AnchorWidget.prototype.refreshNeighbors_ = function (selected) { - var options = document.querySelectorAll('.'+OPTION_CLASSNAME); - for (var i = 0 ; i < options.length ; i++) { - options[i].removeAttribute('data-neighbor'); - } - - var selectedIndex = Array.prototype.indexOf.call(options, selected); - - this.setNeighborhood_(options[selectedIndex - 1], 'left'); - this.setNeighborhood_(options[selectedIndex + 1], 'right'); - this.setNeighborhood_(options[selectedIndex - 3], 'top'); - this.setNeighborhood_(options[selectedIndex + 3], 'bottom'); - }; - - ns.AnchorWidget.prototype.setNeighborhood_ = function (el, neighborhood) { - var origin = this.origin.toLowerCase(); - var isNeighborhoodValid = origin.indexOf(neighborhood) === -1; - if (isNeighborhoodValid) { - el.setAttribute('data-neighbor', neighborhood); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.ResizeController = function (piskelController) { - this.piskelController = piskelController; - - this.container = document.querySelector('.resize-canvas'); - - var anchorWidgetContainer = this.container.querySelector('.resize-origin-container'); - this.anchorWidget = new ns.AnchorWidget(anchorWidgetContainer); - }; - - pskl.utils.inherit(ns.ResizeController, pskl.controller.settings.AbstractSettingController); - - ns.ResizeController.prototype.init = function () { - this.widthInput = this.container.querySelector('[name="resize-width"]'); - this.heightInput = this.container.querySelector('[name="resize-height"]'); - - this.widthInput.value = this.piskelController.getWidth(); - this.heightInput.value = this.piskelController.getHeight(); - - this.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_); - this.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_); - - this.resizeForm = this.container.querySelector('form'); - this.addEventListener(this.resizeForm, 'submit', this.onResizeFormSubmit_); - - this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox'); - this.addEventListener(this.resizeContentCheckbox, 'change', this.onResizeContentChange_); - - this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox'); - this.addEventListener(this.maintainRatioCheckbox, 'change', this.onMaintainRatioChange_); - - this.anchorWidget.setOrigin(ns.AnchorWidget.ORIGIN.TOPLEFT); - this.lastInput = this.widthInput; - }; - - ns.ResizeController.prototype.destroy = function () { - this.anchorWidget.destroy(); - this.superclass.destroy.call(this); - }; - - ns.ResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.preventDefault(); - - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - - ns.ResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.ResizeController.prototype.onResizeContentChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.anchorWidget.disable(); - } else { - this.anchorWidget.enable(); - } - }; - - ns.ResizeController.prototype.onMaintainRatioChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.synchronizeSizeInputs_(this.lastInput); - } - }; - - ns.ResizeController.prototype.onSizeInputKeyUp_ = function (evt) { - var target = evt.target; - if (this.maintainRatioCheckbox.checked) { - this.synchronizeSizeInputs_(target); - } - this.lastInput = target; - }; - - /** - * Based on the value of the provided sizeInput (considered as emitter) - * update the value of the other sizeInput to match the current width/height ratio - * @param {HTMLElement} origin either widthInput or heightInput - */ - ns.ResizeController.prototype.synchronizeSizeInputs_ = function (sizeInput) { - var value = parseInt(sizeInput.value, 10); - if (isNaN(value)) { - value = 0; - } - - var height = this.piskelController.getHeight(), - width = this.piskelController.getWidth(); - - if (sizeInput === this.widthInput) { - this.heightInput.value = Math.round(value * height/width); - } else if (sizeInput === this.heightInput) { - this.widthInput.value = Math.round(value * width/height); - } - }; - - /***********************/ - /* RESIZE LOGIC */ - /***********************/ - - ns.ResizeController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.widthInput.value, 10); - var height = parseInt(this.heightInput.value, 10); - if (this.resizeContentCheckbox.checked) { - return pskl.utils.FrameUtils.resize(frame, width, height, false); - } else { - var resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - var translated = this.translateCoordinates_(x, y, frame, resizedFrame); - if (resizedFrame.containsPixel(translated.x, translated.y)) { - resizedFrame.setPixel(translated.x, translated.y, color); - } - }.bind(this)); - - return resizedFrame; - } - }; - - ns.ResizeController.prototype.translateCoordinates_ = function (x, y, frame, resizedFrame) { - return { - x : this.translateX_(x, frame.width, resizedFrame.width), - y : this.translateY_(y, frame.height, resizedFrame.height) - }; - }; - - ns.ResizeController.prototype.translateX_ = function (x, width, resizedWidth) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('LEFT') != -1) { - return x; - } else if (origin.indexOf('RIGHT') != -1) { - return x - (width - resizedWidth); - } else { - return x - Math.round((width - resizedWidth)/2); - } - }; - - ns.ResizeController.prototype.translateY_ = function (y, height, resizedHeight) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('TOP') != -1) { - return y; - } else if (origin.indexOf('BOTTOM') != -1) { - return y - (height - resizedHeight); - } else { - return y - Math.round((height - resizedHeight)/2); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.SaveController, pskl.controller.settings.AbstractSettingController); - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - // timestamp used to generate unique name when saving as .piskel - this.timestamp = new Date(); - - // Only available in app-engine mode - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = document.querySelector('#save-online-status'); - this.saveFileStatus = document.querySelector('#save-file-status'); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = document.querySelector('#save-description'); - this.descriptionInput.value = descriptor.description; - - this.isPublicCheckbox = document.querySelector('input[name=save-public-checkbox]'); - if (descriptor.isPublic) { - this.isPublicCheckbox.setAttribute('checked', true); - } - - this.addEventListener('#save-file-button', 'click', this.saveFile_); - this.addEventListener('#save-browser-button', 'click', this.saveLocal_); - - this.saveOnlineButton = document.querySelector('#save-online-button'); - this.addEventListener(this.saveOnlineButton, 'click', this.saveOnline_); - - this.addEventListener('form[name=save-form]', 'submit', this.onSaveFormSubmit_); - - this.nameInput = document.querySelector('#save-name'); - this.nameInput.value = descriptor.name; - this.addEventListener(this.nameInput, 'keyup', this.updateLocalStatusFilename_); - - if (pskl.app.isLoggedIn()) { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-online-status-partial'); - } else { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-please-login-partial'); - var container = document.querySelector('.setting-save-section'); - container.classList.add('anonymous'); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.innerHTML = pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - }); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.innerHTML = 'Saving ...'; - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.value; - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.value; - }; - - ns.SaveController.prototype.isPublic_ = function () { - return !!this.isPublicCheckbox.checked; - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.innerHTML = ''; - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.ImportController, pskl.controller.settings.AbstractSettingController); - - ns.ImportController.prototype.init = function () { - this.hiddenFileInput = document.querySelector('[name="file-upload-input"]'); - this.addEventListener(this.hiddenFileInput, 'change', this.onFileUploadChange_); - - this.hiddenOpenPiskelInput = document.querySelector('[name="open-piskel-input"]'); - this.addEventListener(this.hiddenOpenPiskelInput, 'change', this.onOpenPiskelChange_); - - this.addEventListener('.browse-local-button', 'click', this.onBrowseLocalClick_); - this.addEventListener('.file-input-button', 'click', this.onFileInputClick_); - this.addEventListener('.open-piskel-button', 'click', this.onOpenPiskelClick_); - - this.initRestoreSession_(); - }; - - ns.ImportController.prototype.initRestoreSession_ = function () { - var previousSessionContainer = document.querySelector('.previous-session'); - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var previousSessionTemplate_ = pskl.utils.Template.get('previous-session-info-template'); - var date = pskl.utils.DateUtils.format(previousInfo.date, '{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}'); - previousSessionContainer.innerHTML = pskl.utils.Template.replace(previousSessionTemplate_, { - name : previousInfo.name, - date : date - }); - this.addEventListener('.restore-session-button', 'click', this.onRestorePreviousSessionClick_); - } else { - previousSessionContainer.innerHTML = 'No piskel backup was found on this browser.'; - } - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - var files = this.hiddenOpenPiskelInput.files; - if (files.length == 1) { - this.openPiskelFile_(files[0]); - } - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function (file) { - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - this.closeDrawer_(); - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.resize.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.exportimage.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - if (this.currentController && this.currentController.destroy) { - this.currentController.destroy(); - } - - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - - this.currentSetting = setting; - this.currentController = new settings[setting].controller(this.piskelController); - this.currentController.init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - this.destroy(); - $.publish(Events.DIALOG_HIDE); - }; - - ns.AbstractDialogController.prototype.setTitle = function (title) { - var dialogTitle = document.querySelector('.dialog-title'); - if (dialogTitle) { - dialogTitle.innerText = title; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteController = function (piskelController) { - this.paletteService = pskl.app.paletteService; - this.paletteImportService = pskl.app.paletteImportService; - }; - - pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - - ns.CreatePaletteController.prototype.init = function (paletteId) { - this.superclass.init.call(this); - - this.hiddenFileInput = document.querySelector('.create-palette-import-input'); - this.nameInput = document.querySelector('input[name="palette-name"]'); - - var buttonsContainer = document.querySelector('.create-palette-actions'); - var deleteButton = document.querySelector('.create-palette-delete'); - var downloadButton = document.querySelector('.create-palette-download-button'); - var importFileButton = document.querySelector('.create-palette-import-button'); - - this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); - this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - - buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this)); - downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this)); - importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); - - var colorsListContainer = document.querySelector('.colors-container'); - this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer); - - var palette; - var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID; - if (paletteId && !isCurrentColorsPalette) { - importFileButton.style.display = 'none'; - this.setTitle('Edit Palette'); - - var paletteObject = this.paletteService.getPaletteById(paletteId); - palette = pskl.model.Palette.fromObject(paletteObject); - } else { - downloadButton.style.display = 'none'; - deleteButton.style.display = 'none'; - this.setTitle('Create Palette'); - - var uuid = pskl.utils.Uuid.generate(); - if (isCurrentColorsPalette) { - palette = new pskl.model.Palette(uuid, 'Current colors clone', this.getCurrentColors_()); - } else { - palette = new pskl.model.Palette(uuid, 'New palette', []); - } - } - - this.setPalette_(palette); - }; - - ns.CreatePaletteController.prototype.getCurrentColors_ = function () { - var palette = this.paletteService.getPaletteById(Constants.CURRENT_COLORS_PALETTE_ID); - return palette.getColors(); - }; - - ns.CreatePaletteController.prototype.setPalette_ = function (palette) { - this.palette = palette; - this.nameInput.value = pskl.utils.unescapeHtml(palette.name); - this.colorsListWidget.setColors(palette.getColors()); - }; - - ns.CreatePaletteController.prototype.destroy = function () { - this.colorsListWidget.destroy(); - this.nameInput = null; - }; - - ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) { - var target = evt.target; - if (target.dataset.action === 'submit') { - this.saveAndSelectPalette_(); - } else if (target.dataset.action === 'cancel') { - this.closeDialog(); - } else if (target.dataset.action === 'delete') { - this.deletePalette_(); - } - }; - - ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function () { - this.palette.setColors(this.colorsListWidget.getColors()); - this.paletteService.savePalette(this.palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, this.palette.id); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.deletePalette_ = function () { - if (window.confirm('Are you sure you want to delete palette ' + this.palette.name)) { - this.paletteService.deletePaletteById(this.palette.id); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, Constants.CURRENT_COLORS_PALETTE_ID); - this.closeDialog(); - } - }; - - ns.CreatePaletteController.prototype.onDownloadButtonClick_ = function () { - var paletteWriter = new pskl.service.palette.PaletteGplWriter(this.palette); - var paletteAsString = paletteWriter.write(); - - pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.palette.name + '.gpl'); - }.bind(this), "application/json"); - }; - - ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { - this.hiddenFileInput.click(); - }; - - ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - this.paletteImportService.read(files[0], this.setPalette_.bind(this), this.displayErrorMessage_.bind(this)); - } - }; - - ns.CreatePaletteController.prototype.displayErrorMessage_ = function (message) { - message = "Could not import palette : " + message; - $.publish(Events.SHOW_NOTIFICATION, [{"content": message}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { - this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (image) { - this.importedImage_ = image; - - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.utils.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'create-palette' : { - template : 'templates/dialogs/create-palette.html', - controller : ns.CreatePaletteController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette')); - - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.classList.add(dialogId); - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - var DEFAULT_COLOR = '#000000'; - - ns.ColorsList = function (container) { - this.selectedIndex = -1; - this.palette = new pskl.model.Palette('tmp', 'tmp', []); - this.container = container; - - this.colorsList = this.container.querySelector('.colors-list'); - this.colorPreviewEl = this.container.querySelector('.color-preview'); - - $(container).sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onColorDrop_.bind(this), - items: '.create-palette-color' - }); - - this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - - var colorPickerContainer = container.querySelector('.color-picker-container'); - this.hslRgbColorPicker = new pskl.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); - this.hslRgbColorPicker.init(); - }; - - ns.ColorsList.prototype.setColors = function (colors) { - if (colors.length === 0) { - colors.push(DEFAULT_COLOR); - } - - this.palette.setColors(colors); - - this.selectColor_(0); - this.refresh_(); - }; - - ns.ColorsList.prototype.getColors = function () { - return this.palette.getColors(); - }; - - ns.ColorsList.prototype.destroy = function () { - this.hslRgbColorPicker.destroy(); - this.container = null; - this.colorsList = null; - this.colorPreviewEl = null; - }; - - /** - * Lightweight refresh only changing the color of one element of the palette color list - */ - ns.ColorsList.prototype.refreshColorElement_ = function (index) { - var color = this.palette.get(this.selectedIndex); - var element = document.querySelector('[data-palette-index="'+index+'"]'); - if (element) { - element.style.background = color; - element.classList.toggle('light-color', this.isLight_(color)); - } - }; - - ns.ColorsList.prototype.onColorContainerClick_ = function (evt) { - var target = evt.target; - if (target.classList.contains('create-palette-color')) { - this.onPaletteColorClick_(evt, target); - } else if (target.classList.contains('create-palette-new-color')) { - this.onNewColorClick_(evt, target); - } else if (target.classList.contains('create-palette-remove-color')) { - this.onRemoveColorClick_(evt, target); - } - this.refresh_(); - }; - - ns.ColorsList.prototype.onColorUpdated_ = function (color) { - var rgbColor = color.toRgbString(); - this.colorPreviewEl.style.background = rgbColor; - if (this.palette) { - this.palette.set(this.selectedIndex, rgbColor); - this.refreshColorElement_(this.selectedIndex); - } - }; - - ns.ColorsList.prototype.onPaletteColorClick_ = function (evt, target) { - var index = parseInt(target.dataset.paletteIndex,10); - this.selectColor_(index); - }; - - ns.ColorsList.prototype.onRemoveColorClick_ = function (evt, target) { - var colorElement = target.parentNode; - var index = parseInt(colorElement.dataset.paletteIndex,10); - this.removeColor_(index); - }; - - ns.ColorsList.prototype.onNewColorClick_ = function (evt, target) { - var newColor = this.palette.get(this.selectedIndex) || '#000000'; - this.palette.add(newColor); - this.selectColor_(this.palette.size()-1); - }; - - ns.ColorsList.prototype.refresh_ = function () { - var html = ""; - var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.getColors(); - - colors.forEach(function (color, index) { - var isSelected = (index === this.selectedIndex); - - html += pskl.utils.Template.replace(tpl, { - 'color':color, index:index, - ':selected':isSelected, - ':light-color':this.isLight_(color) - }); - }.bind(this)); - - html += '
      • +
      • '; - - this.colorsList.innerHTML = html; - }; - - ns.ColorsList.prototype.selectColor_ = function (index) { - this.selectedIndex = index; - this.hslRgbColorPicker.setColor(this.palette.get(index)); - }; - - ns.ColorsList.prototype.removeColor_ = function (index) { - this.palette.removeAt(index); - this.refresh_(); - }; - - ns.ColorsList.prototype.isLight_ = function (color) { - var rgb = window.tinycolor(color).toRgb(); - return rgb.r+rgb.b+rgb.g > 128*3; - }; - - ns.ColorsList.prototype.onColorDrop_ = function (evt, drop) { - var colorElement = drop.item.get(0); - - var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); - var newIndex = $('.create-palette-color').index(drop.item); - this.palette.move(oldIndex, newIndex); - - this.selectedIndex = newIndex; - - this.refresh_(); - }; -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { - this.container = container; - this.colorUpdatedCallback = colorUpdatedCallback; - - this.tinyColor = null; - this.hsvColor = null; - this.rgbColor = null; - - this.lastInputTimestamp_ = 0; - }; - - ns.HslRgbColorPicker.prototype.init = function () { - var isChromeOrFirefox = pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isFirefox; - var changeEvent = isChromeOrFirefox ? 'input' : 'change'; - this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this)); - this.container.addEventListener('keydown', this.onKeydown_.bind(this)); - this.container.addEventListener('focusout', this.onBlur_.bind(this)); - - this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); - - $(this.spectrumEl).spectrum({ - flat: true, - showButtons: false, - move : this.setColor.bind(this), - change : this.setColor.bind(this) - }); - - this.setColor("#000000"); - }; - - ns.HslRgbColorPicker.prototype.destroy = function () { - this.container = null; - this.spectrumEl = null; - }; - - ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) { - var target = evt.target; - if (target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = target.value; - - this.updateColor_(value, model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.onKeydown_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - - if (model === 'rgb' || model === 'hsv') { - var increment = this.getIncrement_(evt); - if (increment) { - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - this.updateColor_(value + increment, model, dimension); - } - } - } - }; - - ns.HslRgbColorPicker.prototype.getIncrement_ = function (evt) { - var increment = 0; - var key = pskl.service.keyboard.KeycodeTranslator.toChar(evt.keyCode); - if (key === 'up') { - increment = 1; - } else if (key === 'down') { - increment = -1; - } - - if (evt.shiftKey) { - increment = increment * 5; - } - - return increment; - }; - - ns.HslRgbColorPicker.prototype.updateColor_ = function (inputValue, model, dimension) { - var value = this.toModelValue_(inputValue, model, dimension); - if (model === 'hsv' || model === 'rgb') { - if (!isNaN(value)) { - var color = this.getColor_(model); - color[dimension] = this.normalizeDimension_(value, dimension); - this.setColor(color); - } - } else if (model === 'hex') { - if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) { - this.setColor(value); - } - } - }; - - ns.HslRgbColorPicker.prototype.onBlur_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - target.value = this.toInputValue_(model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - this.rgbColor = this.tinyColor.toRgb(); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.colorUpdatedCallback(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.HslRgbColorPicker.prototype.updateInputs = function () { - var inputs = this.container.querySelectorAll('input'); - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - var value = this.toInputValue_(model, dimension); - if (input.value != value) { - input.value = value; - } - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.HslRgbColorPicker.prototype.toInputValue_ = function (model, dimension) { - var value; - - if (model === 'rgb' || model === 'hsv') { - var color = this.getColor_(model); - value = color[dimension]; - - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - value = Math.round(value); - } else if (model === 'hex') { - value = this.tinyColor.toHexString(true); - } - - return value; - }; - - ns.HslRgbColorPicker.prototype.toModelValue_ = function (value, model, dimension) { - var modelValue; - - if (model === 'rgb' || model === 'hsv') { - modelValue = parseInt(value, 10); - if (dimension === 'v' || dimension === 's') { - modelValue = modelValue/100; - } - } else if (model === 'hex') { - modelValue = value; - } - - return modelValue; - }; - - ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { - var isTinyColor = typeof color == 'object' && color.hasOwnProperty('_tc_id'); - if (isTinyColor) { - return color; - } else { - return window.tinycolor(pskl.utils.copy(color)); - } - }; - - ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : this.normalizeDimension_(color.h, 'h'), - s : this.normalizeDimension_(color.s, 's'), - v : this.normalizeDimension_(color.v, 'v') - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) { - var range = this.getDimensionRange_(dimension); - return Math.max(range[0], Math.min(range[1], value)); - }; - - /** - * Update background colors for range inputs - */ - ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - var colors = this.getSliderBackgroundColors_(model, dimension); - slider.style.backgroundImage = "linear-gradient(to right, " + colors.start + " 0, " + colors.end + " 100%)"; - } - }; - - ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) { - var color = this.getColor_(model); - var start = pskl.utils.copy(color); - var end = pskl.utils.copy(color); - - var range = this.getDimensionRange_(dimension); - start[dimension] = range[0]; - end[dimension] = range[1]; - - return { - start : window.tinycolor(start).toRgbString(), - end : window.tinycolor(end).toRgbString() - }; - }; - - ns.HslRgbColorPicker.prototype.getDimensionRange_ = function (d) { - if (d === 'h') { - return [0, 359]; - } else if (d === 's' || d === 'v') { - return [0, 1]; - } else if (d === 'r' || d === 'g' || d === 'b') { - return [0, 255]; - } - }; - - ns.HslRgbColorPicker.prototype.getColor_ = function (model) { - var color; - if (model === 'hsv') { - color = this.hsvColor; - } else if (model === 'rgb'){ - color = this.rgbColor; - } - return color; - }; - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var data = { - framesheet : this.piskelController.serialize(), - fps : this.piskelController.getFPS(), - name : descriptor.name, - description : descriptor.description, - frames : this.piskelController.getFrameCount(), - first_frame_as_png : pskl.app.getFirstFrameAsPng(), - framesheet_as_png : pskl.app.getFramesheetAsPng() - }; - - if (descriptor.isPublic) { - data['public'] = true; - } - - var success = function () { - callbacks.success(); - callbacks.after(); - }; - - var error = function (response) { - callbacks.error(response.status); - callbacks.after(); - }; - - pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - // 1 minute = 1000 * 60 - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - this.savePiskel_('prev', previousPiskel, previousInfo); - } - - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - this.savePiskel_('next', this.piskelController.serialize(), JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(previousInfo.fps); - }); - }; - - ns.BackupService.prototype.savePiskel_ = function (type, piskel, info) { - try { - window.localStorage.setItem('bkp.' + type +'.piskel', piskel); - window.localStorage.setItem('bkp.' + type +'.info', info); - } catch (e) { - console.error('Could not save piskel backup in localStorage.', e); - } - }; -})(); - - - - -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.HistoryService = function (piskelController, shortcutService, deserializer) { - this.piskelController = piskelController || pskl.app.piskelController; - this.shortcutService = shortcutService || pskl.app.shortcutService; - this.deserializer = deserializer || pskl.utils.serialization.Deserializer; - - this.stateQueue = []; - this.currentIndex = -1; - - this.lastLoadState = -1; - }; - - // Force to save a state as a SNAPSHOT - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - - // Default save state - ns.HistoryService.REPLAY = 'REPLAY'; - - // Period (in number of state saved) between two snapshots - ns.HistoryService.SNAPSHOT_PERIOD = 50; - - // Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming) - ns.HistoryService.LOAD_STATE_INTERVAL = 50; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); - - this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, action) { - this.saveState(action); - }; - - ns.HistoryService.prototype.saveState = function (action) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : action, - frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex, - layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = action.type === ns.HistoryService.SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0; - if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - } - - this.stateQueue.push(state); - $.publish(Events.HISTORY_STATE_SAVED); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - // Should only do this when going backwards - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - $.publish(Events.HISTORY_STATE_LOADED); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service.color'); - - var LOW_SAT = 0.1; - var LOW_LUM = 0.1; - var HI_LUM = 0.9; - - - var HUE_STEP = 36; - var HUE_BAGS = 10; - var HUE_BOUNDS = []; - for (var i = 0 ; i < HUE_BAGS ; i++) { - HUE_BOUNDS.push(i * HUE_STEP); - } - - ns.ColorSorter = function () { - this.colorsHslMap_ = {}; - }; - - ns.ColorSorter.prototype.sort = function (colors) { - this.colorsHslMap_ = {}; - - colors.forEach(function (color) { - this.colorsHslMap_[color] = window.tinycolor(color).toHsl(); - }.bind(this)); - - // sort by most frequent color - var darkColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l <= LOW_LUM; - }.bind(this)); - - var brightColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l >= HI_LUM; - }.bind(this)); - - var desaturatedColors = colors.filter(function (c) { - return brightColors.indexOf(c) === -1 && darkColors.indexOf(c) === -1; - }).filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.s <= LOW_SAT; - }.bind(this)); - - darkColors = this.sortOnHslProperty_(darkColors, 'l'); - brightColors = this.sortOnHslProperty_(brightColors, 'l'); - desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); - - var sortedColors = darkColors.concat(brightColors, desaturatedColors); - - var regularColors = colors.filter(function (c) { - return sortedColors.indexOf(c) === -1; - }); - - var regularColorsBags = HUE_BOUNDS.map(function (hue) { - var bagColors = regularColors.filter(function (color) { - var hsl = this.colorsHslMap_[color]; - return (hsl.h >= hue && hsl.h < hue + HUE_STEP); - }.bind(this)); - - return this.sortRegularColors_(bagColors); - }.bind(this)); - - return Array.prototype.concat.apply(sortedColors, regularColorsBags); - }; - - ns.ColorSorter.prototype.sortRegularColors_ = function (colors) { - var sortedColors = colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - var hDiff = Math.abs(hsl1.h - hsl2.h); - var sDiff = Math.abs(hsl1.s - hsl2.s); - var lDiff = Math.abs(hsl1.l - hsl2.l); - if (hDiff < 10) { - if (sDiff > lDiff) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - return this.compareValues_(hsl1.l, hsl2.l); - } - } else { - return this.compareValues_(hsl1.h, hsl2.h); - } - }.bind(this)); - - return sortedColors; - }; - - ns.ColorSorter.prototype.sortOnHslProperty_ = function (colors, property) { - return colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - return this.compareValues_(hsl1[property], hsl2[property]); - }.bind(this)); - }; - - ns.ColorSorter.prototype.compareValues_ = function (v1, v2) { - if (v1 > v2) { - return 1; - } else if (v1 < v2) { - return -1; - } - return 0; - }; - -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.CurrentColorsPalette = function () { - this.name = 'Current colors'; - this.id = Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsPalette.prototype.getColors = function () { - return pskl.app.currentColorsService.getCurrentColors(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteService = function () { - this.dynamicPalettes = []; - this.localStorageService = window.localStorage; - }; - - ns.PaletteService.prototype.getPalettes = function () { - var palettesString = this.localStorageService.getItem('piskel.palettes'); - var palettes = JSON.parse(palettesString) || []; - palettes = palettes.map(function (palette) { - return pskl.model.Palette.fromObject(palette); - }); - - return this.dynamicPalettes.concat(palettes); - }; - - ns.PaletteService.prototype.getPaletteById = function (paletteId) { - var palettes = this.getPalettes(); - return this.findPaletteInArray_(paletteId, palettes); - }; - - ns.PaletteService.prototype.savePalette = function (palette) { - var palettes = this.getPalettes(); - var existingPalette = this.findPaletteInArray_(palette.id, palettes); - if (existingPalette) { - var currentIndex = palettes.indexOf(existingPalette); - palettes.splice(currentIndex, 1, palette); - } else { - palettes.push(palette); - } - - this.savePalettes_(palettes); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteService.prototype.addDynamicPalette = function (palette) { - this.dynamicPalettes.push(palette); - }; - - ns.PaletteService.prototype.deletePaletteById = function (id) { - var palettes = this.getPalettes(); - var filteredPalettes = palettes.filter(function (palette) { - return palette.id !== id; - }); - - this.savePalettes_(filteredPalettes); - }; - - ns.PaletteService.prototype.savePalettes_ = function (palettes) { - palettes = palettes.filter(function (palette) { - return this.dynamicPalettes.indexOf(palette) === -1; - }.bind(this)); - this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteGplWriter = function (palette) { - this.palette = palette; - }; - - ns.PaletteGplWriter.prototype.write = function () { - var lines = []; - lines.push('GIMP Palette'); - lines.push('Name: ' + this.palette.name); - lines.push('Columns: 0'); - lines.push('#'); - this.palette.getColors().forEach(function (color) { - lines.push(this.writeColorLine(color)); - }.bind(this)); - lines.push('\r\n'); - - return lines.join('\r\n'); - }; - - ns.PaletteGplWriter.prototype.writeColorLine = function (color) { - var tinycolor = window.tinycolor(color); - var rgb = tinycolor.toRgb(); - var strBuffer = []; - strBuffer.push(this.padString(rgb.r, 3)); - strBuffer.push(this.padString(rgb.g, 3)); - strBuffer.push(this.padString(rgb.b, 3)); - strBuffer.push('Untitled'); - - return strBuffer.join(' '); - }; - - ns.PaletteGplWriter.prototype.padString = function (str, size) { - str = str.toString(); - var pad = (new Array(1+size-str.length)).join(' '); - return pad + str; - }; - -})(); -;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.AbstractPaletteFileReader = function (file, onSuccess, onError, colorLineRegexp) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - this.colorLineRegexp = colorLineRegexp; - }; - - ns.AbstractPaletteFileReader.prototype.extractColorFromLine = Constants.ABSTRACT_FUNCTION; - - ns.AbstractPaletteFileReader.prototype.read = function () { - pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this)); - }; - - ns.AbstractPaletteFileReader.prototype.onFileLoaded_ = function (content) { - var text = pskl.utils.Base64.toText(content); - var lines = text.match(/[^\r\n]+/g); - - var colorLines = lines.filter(function (l) { - return this.colorLineRegexp.test(l); - }.bind(this)); - - var colors = colorLines.map(this.extractColorFromLine.bind(this)); - - if (colors.length) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name, colors); - this.onSuccess(palette); - } else { - this.onError(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/; - var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; - - ns.PaletteGplReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteGplReader, ns.AbstractPaletteFileReader); - - ns.PaletteGplReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = window.tinycolor({ - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10) - }); - - return color.toRgbString(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.PaletteImageReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - - this.colorSorter_ = new pskl.service.color.ColorSorter(); - }; - - ns.PaletteImageReader.prototype.read = function () { - pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this)); - }; - - ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) { - var imageProcessor = new pskl.worker.ImageProcessor(image, - this.onWorkerSuccess_.bind(this), - this.onWorkerStep_.bind(this), - this.onWorkerError_.bind(this)); - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]); - - imageProcessor.process(); - }; - - ns.PaletteImageReader.prototype.onWorkerSuccess_ = function (event) { - var data = event.data; - var colorsMap = data.colorsMap; - - var colors = Object.keys(colorsMap); - - if (colors.length > 200) { - this.onError('Too many colors : ' + colors.length); - } else { - var uuid = pskl.utils.Uuid.generate(); - var sortedColors = this.colorSorter_.sort(colors); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', sortedColors); - - this.onSuccess(palette); - } - $.publish(Events.HIDE_PROGRESS); - }; - - ns.PaletteImageReader.prototype.onWorkerStep_ = function (event) { - var progress = event.data.progress; - $.publish(Events.UPDATE_PROGRESS, [{"progress": progress}]); - }; - - ns.PaletteImageReader.prototype.onWorkerError_ = function (event) { - $.publish(Events.HIDE_PROGRESS); - this.onError('Unable to process the image : ' + event.data.message); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})/; - - ns.PalettePalReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PalettePalReader, ns.AbstractPaletteFileReader); - - ns.PalettePalReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = 'rgb(' + matches[1] + ',' + matches[2] + ',' + matches[3] + ')'; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/; - - ns.PaletteTxtReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteTxtReader, ns.AbstractPaletteFileReader); - - ns.PaletteTxtReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = "#" + matches[1] + matches[2] + matches[3]; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var fileReaders = { - 'gpl' : ns.reader.PaletteGplReader, - 'pal' : ns.reader.PalettePalReader, - 'txt' : ns.reader.PaletteTxtReader, - 'img' : ns.reader.PaletteImageReader - }; - - ns.PaletteImportService = function () {}; - - ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader = this.getReader_(file, onSuccess, onError); - if (reader) { - reader.read(); - } else { - throw 'Could not find reader for file : ' + file.name; - } - }; - - ns.PaletteImportService.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.PaletteImportService.prototype.getReader_ = function (file, onSuccess, onError) { - var readerClass = this.getReaderClass_(file); - if (readerClass) { - return new readerClass(file, onSuccess, onError); - } else { - return null; - } - }; - - ns.PaletteImportService.prototype.getReaderClass_ = function (file) { - var readerClass; - if (this.isImage_(file)) { - readerClass = fileReaders.img; - } else { - var extension = this.getExtension_(file); - readerClass = fileReaders[extension]; - } - return readerClass; - }; - - ns.PaletteImportService.prototype.getExtension_ = function (file) { - var parts = file.name.split('.'); - var extension = parts[parts.length-1]; - return extension.toLowerCase(); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.addShortcuts = function (keys, callback) { - keys.forEach(function (key) { - this.addShortcut(key, callback); - }.bind(this)); - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+", - 188 : "<", - 190 : ">" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Create a Palette'), - this.toDescriptor_('</>', 'Select previous/next palette color'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} success success callback. 1st argument will be the uploaded image URL - * @param {Function} error error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, success, error) { - var data = { - data : imageData - }; - - var wrappedSuccess = function (response) { - success(Constants.IMAGE_SERVICE_GET_URL + response.responseText); - }; - - pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - // cache of current colors by history state - this.cache = {}; - this.currentColors = []; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); - - this.colorSorter = new pskl.service.color.ColorSorter(); - this.paletteService = pskl.app.paletteService; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.HISTORY_STATE_SAVED, this.updateCurrentColors_.bind(this)); - $.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.setCurrentColors = function (colors) { - var historyIndex = pskl.app.historyService.currentIndex; - this.cache[historyIndex] = colors; - if (colors.join('') !== this.currentColors.join('')) { - this.currentColors = colors; - $.publish(Events.CURRENT_COLORS_UPDATED); - } - }; - - ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); - - return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsService.prototype.loadColorsFromCache_ = function () { - var historyIndex = pskl.app.historyService.currentIndex; - var colors = this.cache[historyIndex]; - if (colors) { - this.setCurrentColors(colors); - } - }; - - ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = true; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - var currentColors = this.colorSorter.sort(colorsArray); - - this.setCurrentColors(currentColors); - }; - - ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexString_(color); - frameColors[hexColor] = true; - }.bind(this)); - return frameColors; - }; - - ns.CurrentColorsService.prototype.toHexString_ = function (color) { - if (color === Constants.TRANSPARENT_COLOR) { - return color; - } else { - color = color.replace(/\s/g, ''); - var hexRe = (/^#([a-f0-9]{3}){1,2}$/i); - var rgbRe = (/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i); - if (hexRe.test(color)) { - return color.toUpperCase(); - } else if (rgbRe.test(color)) { - var exec = rgbRe.exec(color); - return pskl.utils.rgbToHex(exec[1] * 1, exec[2] * 1, exec[3] * 1); - } else { - console.error('Could not convert color to hex : ', color); - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - var isPiskel = /\.piskel$/i.test(file.name); - var isPalette = /\.(gpl|txt|pal)$/i.test(file.name); - if (isImage) { - this.readImageFile_(file); - } else if (isPiskel) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } else if (isPalette) { - pskl.app.paletteImportService.read(file, this.onPaletteLoaded_.bind(this)); - } - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.onPaletteLoaded_ = function (palette) { - pskl.app.paletteService.savePalette(palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.Tool = function () { - this.toolId = "tool"; - this.helpText = "Abstract tool"; - this.tooltipDescriptors = []; - }; - - ns.Tool.prototype.getHelpText = function() { - return this.helpText; - }; - - ns.Tool.prototype.getId = function() { - return this.toolId; - }; -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.IconMarkupRenderer = function () {}; - - ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) { - tooltipPosition = tooltipPosition || 'right'; - shortcut = shortcut ? '(' + shortcut + ')' : ''; - var tpl = pskl.utils.Template.get('drawingTool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : ['tool-icon', tool.toolId].join(' '), - toolid : tool.toolId, - title : this.getTooltipText(tool, shortcut), - tooltipposition : tooltipPosition - }); - }; - - ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) { - var descriptors = tool.tooltipDescriptors; - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : tool.getHelpText(), - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.IconMarkupRenderer.prototype.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.IconMarkupRenderer.prototype.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;/** - * @provide pskl.tools.drawing.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.BaseTool = function() { - pskl.tool.Tool.call(this); - this.toolId = "tool-base"; - }; - - pskl.utils.inherit(ns.BaseTool, pskl.tools.Tool); - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.tools.drawing'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [coords.col, coords.row]); - this.raiseSaveStateEvent({ - col : coords.col, - row : coords.row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.tools.drawing.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i 0) { - var node = this; - for (var i = 0 ; i < parts.length ; i++) { - if (!node[parts[i]]) { - node[parts[i]] = {}; - } - node = node[parts[i]]; - } - } - }); - var script = createNamespace + ""; - script = script.replace(/function \(\) \{/,"").replace(/\}[^}]*$/, ""); - script = "var name = '" + name + "';" + script; - - this.runScript(script); - }; - - ns.ImageProcessor.prototype.onWorkerMessage = function (event) { - if (event.data.type === 'STEP') { - this.onStep(event); - } else if (event.data.type === 'SUCCESS') { - this.onSuccess(event); - this.worker.terminate(); - } else if (event.data.type === 'ERROR') { - this.onError(event); - this.worker.terminate(); - } - }; - - ns.ImageProcessor.prototype.importAll__ = function (classToImport, classpath) { - this.createNamespace(classpath); - for (var key in classToImport) { - if (classToImport.hasOwnProperty(key)) { - this.addMethod(classToImport[key], classpath + '.' + key); - } - } - }; - - ns.ImageProcessor.prototype.addMethod__ = function (method, name) { - this.runScript(name + "=" + method); - }; - - ns.ImageProcessor.prototype.runScript__ = function (script) { - this.worker.postMessage({ - type : 'RUN_SCRIPT', - script : this.getScriptAsUrl(script) - }); - }; - - ns.ImageProcessor.prototype.getScriptAsUrl__ = function (script) { - var blob = new Blob([script], {type: "application/javascript"}); // pass a useful mime type here - return window.URL.createObjectURL(blob); - }; -})(); - - - -;/** - * @require Constants - * @require Events - */ -(function () { - var ns = $.namespace("pskl"); - /** - * Main application controller - */ - ns.app = { - - init : function () { - /** - * When started from APP Engine, appEngineToken_ (Boolean) should be set on window.pskl - */ - this.isAppEngineVersion = !!pskl.appEngineToken_; - - this.shortcutService = new pskl.service.keyboard.ShortcutService(); - this.shortcutService.init(); - - var size = { - height : Constants.DEFAULT.HEIGHT, - width : Constants.DEFAULT.WIDTH - }; - - var descriptor = new pskl.model.piskel.Descriptor('New Piskel', ''); - var piskel = new pskl.model.Piskel(size.width, size.height, descriptor); - - var layer = new pskl.model.Layer("Layer 1"); - var frame = new pskl.model.Frame(size.width, size.height); - - layer.addFrame(frame); - piskel.addLayer(layer); - - this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel); - this.corePiskelController.init(); - - this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); - this.piskelController.init(); - - this.paletteImportService = new pskl.service.palette.PaletteImportService(); - this.paletteService = new pskl.service.palette.PaletteService(); - this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette()); - - this.paletteController = new pskl.controller.PaletteController(); - this.paletteController.init(); - - this.currentColorsService = new pskl.service.CurrentColorsService(this.piskelController); - this.currentColorsService.init(); - - this.palettesListController = new pskl.controller.PalettesListController(this.paletteController, this.currentColorsService); - this.palettesListController.init(); - - this.cursorCoordinatesController = new pskl.controller.CursorCoordinatesController(this.piskelController); - this.cursorCoordinatesController.init(); - - this.drawingController = new pskl.controller.DrawingController(this.piskelController, this.paletteController, $('#drawing-canvas-container')); - this.drawingController.init(); - - this.previewController = new pskl.controller.preview.PreviewController(this.piskelController, $('#animated-preview-canvas-container')); - this.previewController.init(); - - this.minimapController = new pskl.controller.MinimapController(this.piskelController, this.previewController, this.drawingController, $('.minimap-container')); - this.minimapController.init(); - - this.framesListController = new pskl.controller.FramesListController(this.piskelController, $('#preview-list')); - this.framesListController.init(); - - this.layersListController = new pskl.controller.LayersListController(this.piskelController); - this.layersListController.init(); - - this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController); - this.settingsController.init(); - - this.dialogsController = new pskl.controller.dialogs.DialogsController(this.piskelController); - this.dialogsController.init(); - - this.toolController = new pskl.controller.ToolController(); - this.toolController.init(); - - this.selectionManager = new pskl.selection.SelectionManager(this.piskelController); - this.selectionManager.init(); - - this.historyService = new pskl.service.HistoryService(this.corePiskelController); - this.historyService.init(); - - this.notificationController = new pskl.controller.NotificationController(); - this.notificationController.init(); - - this.transformationsController = new pskl.controller.TransformationsController(); - this.transformationsController.init(); - - this.progressBarController = new pskl.controller.ProgressBarController(); - this.progressBarController.init(); - - this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController(); - this.canvasBackgroundController.init(); - - this.localStorageService = new pskl.service.LocalStorageService(this.piskelController); - this.localStorageService.init(); - - this.imageUploadService = new pskl.service.ImageUploadService(); - this.imageUploadService.init(); - - this.cheatsheetService = new pskl.service.keyboard.CheatsheetService(); - this.cheatsheetService.init(); - - this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController); - this.savedStatusService.init(); - - this.backupService = new pskl.service.BackupService(this.piskelController); - this.backupService.init(); - - this.beforeUnloadService = new pskl.service.BeforeUnloadService(this.piskelController); - this.beforeUnloadService.init(); - - this.fileDropperService = new pskl.service.FileDropperService(this.piskelController, $('#drawing-canvas-container').get(0)); - this.fileDropperService.init(); - - if (this.isAppEngineVersion) { - this.storageService = new pskl.service.AppEngineStorageService(this.piskelController); - } else { - this.storageService = new pskl.service.GithubStorageService(this.piskelController); - } - this.storageService.init(); - - var drawingLoop = new pskl.rendering.DrawingLoop(); - drawingLoop.addCallback(this.render, this); - drawingLoop.start(); - - this.initTooltips_(); - - var piskelData = this.getPiskelInitData_(); - if (piskelData && piskelData.piskel) { - this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); - } - - if (pskl.devtools) { - pskl.devtools.init(); - } - }, - - loadPiskel_ : function (serializedPiskel, descriptor, fps) { - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }, - - getPiskelInitData_ : function () { - return pskl.appEnginePiskelData_; - }, - - isLoggedIn : function () { - var piskelData = this.getPiskelInitData_(); - return piskelData && piskelData.isLoggedIn; - }, - - initTooltips_ : function () { - $('body').tooltip({ - selector: '[rel=tooltip]' - }); - }, - - render : function (delta) { - this.drawingController.render(delta); - this.previewController.render(delta); - this.framesListController.render(delta); - }, - - getFirstFrameAsPng : function () { - var firstFrame = this.piskelController.getFrameAt(0); - var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); - canvasRenderer.drawTransparentAs('rgba(0,0,0,0)'); - var firstFrameCanvas = canvasRenderer.render(); - return firstFrameCanvas.toDataURL("image/png"); - }, - - getFramesheetAsPng : function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - var framesheetCanvas = renderer.renderAsCanvas(); - return framesheetCanvas.toDataURL("image/png"); - } - }; -})(); - -;(function () { - var flipFrame = function (frame, horizontal, vertical) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - clone.forEachPixel(function (color, x, y) { - if (horizontal) { - x = w-x-1; - } - if (vertical) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - }; - - window.flip = function (horizontal, vertical) { - var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex(); - var layers = pskl.app.piskelController.getLayers(); - layers.forEach(function (layer) { - flipFrame(layer.getFrameAt(currentFrameIndex), horizontal, vertical); - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - window.copyToAll = function () { - var ref = pskl.app.piskelController.getCurrentFrame(); - var layer = pskl.app.piskelController.getCurrentLayer(); - layer.getFrames().forEach(function (frame) { - if (frame !== ref) { - frame.setPixels(ref.getPixels()); - } - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; -})(); \ No newline at end of file diff --git a/js/piskel-packaged-2015-03-02-09-41.js b/js/piskel-packaged-2015-03-02-09-41.js deleted file mode 100644 index 336a1d49..00000000 --- a/js/piskel-packaged-2015-03-02-09-41.js +++ /dev/null @@ -1,24855 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing', - - // SERVICE URLS - APPENGINE_SAVE_URL : 'save', - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - SELECT_TOOL : "SELECT_TOOL", - - TOOL_RELEASED : "TOOL_RELEASED", - TOOL_PRESSED : "TOOL_PRESSED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - HISTORY_STATE_SAVED: "HISTORY_STATE_SAVED", - HISTORY_STATE_LOADED: "HISTORY_STATE_LOADED", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - SHOW_PROGRESS: "SHOW_PROGRESS", - UPDATE_PROGRESS: "UPDATE_PROGRESS", - HIDE_PROGRESS: "HIDE_PROGRESS", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", - - MOUSE_EVENT : "MOUSE_EVENT", - - // Tests - TEST_RECORD_END : "TEST_RECORD_END", - TEST_CASE_END : "TEST_CASE_END", - TEST_SUITE_END : "TEST_SUITE_END" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i": ">", - '"': '"', - "'": ''', - "/": '/' - }; - ns.escapeHtml= function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml= function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], "g"); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Array = { - find : function (array, filterFn) { - var match = null; - array = Array.isArray(array) ? array : []; - var filtered = array.filter(filterFn); - if (filtered.length) { - match = filtered[0]; - } - return match; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/,'')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement('canvas'); - canvas.setAttribute('width', width); - canvas.setAttribute('height', height); - - if (typeof classList == 'string') { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.utils.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.utils.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, false); - }, - - enableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, true); - }, - - setImageSmoothing : function (canvas, smoothing) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = smoothing; - context.mozImageSmoothingEnabled = smoothing; - context.oImageSmoothingEnabled = smoothing; - context.webkitImageSmoothingEnabled = smoothing; - context.msImageSmoothingEnabled = smoothing; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.utils.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || 'png'; - var data = canvas.toDataURL('image/' + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Event = {}; - - ns.Event.addEventListener = function (el, type, callback, scope, args) { - if (typeof el === 'string') { - el = document.querySelector(el); - } - - var listener = { - el : el, - type : type, - callback : callback, - handler : args ? callback.bind(scope, args) : callback.bind(scope) - }; - - scope.__pskl_listeners = scope.__pskl_listeners || []; - scope.__pskl_listeners.push(listener); - el.addEventListener(type, listener.handler); - }; - - ns.Event.removeEventListener = function (el, type, callback, scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - if (listener.callback === callback && listener.el === el && listener.type === type) { - el.removeEventListener(type, listeners[i].handler); - listeners.splice(i, 1); - break; - } - } - } - }; - - ns.Event.removeAllEventListeners = function (scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - listener.el.removeEventListener(listener.type, listener.handler); - } - scope.__pskl_listeners = []; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.FrameTransform = { - VERTICAL : 'vertical', - HORIZONTAL : 'HORIZONTAL', - flip : function (frame, axis) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - clone.forEachPixel(function (color, x, y) { - if (axis === ns.FrameTransform.VERTICAL) { - x = w-x-1; - } else if (axis === ns.FrameTransform.HORIZONTAL) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - return frame; - }, - - CLOCKWISE : 'clockwise', - COUNTERCLOCKWISE : 'counterclockwise', - rotate : function (frame, direction) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - var max = Math.max(w, h); - var xDelta = Math.ceil((max - w)/2); - var yDelta = Math.ceil((max - h)/2); - - frame.forEachPixel(function (color, x, y) { - var _x = x, _y = y; - - // Convert to square coords - x = x + xDelta; - y = y + yDelta; - - // Perform the rotation - var tmpX = x, tmpY = y; - if (direction === ns.FrameTransform.CLOCKWISE) { - x = tmpY; - y = max - 1 - tmpX; - } else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) { - y = tmpX; - x = max - 1 - tmpY; - } - - // Convert the coordinates back to the rectangular grid - x = x - xDelta; - y = y - yDelta; - if (clone.containsPixel(x, y)) { - frame.pixels[_x][_y] = clone.getPixel(x, y); - } else { - frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR; - } - }); - frame.version++; - return frame; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - /** - * Render a Frame object as an image. - * Can optionally scale it (zoom) - * @param {Frame} frame - * @param {Number} zoom - * @return {Image} - */ - toImage : function (frame, zoom) { - zoom = zoom || 1; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }, - - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (color, col, row) { - if (color != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, color); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.utils.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); - }, - - createFromImageData_ : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels__ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba__ : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createLayerFromSpritesheet : function (image, frameCount) { - var width = image.width, - height = image.height, - frameWidth = width / frameCount; - - var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, height); - var context = canvas.getContext('2d'); - - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - context.clearRect(0, 0 , frameWidth, height); - context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); - var frame = pskl.utils.FrameUtils.createFromImage(canvas); - frames.push(frame); - } - return frames; - }, - - mergeLayers : function (layerA, layerB) { - var framesA = layerA.getFrames(); - var framesB = layerB.getFrames(); - var mergedFrames = []; - framesA.forEach(function (frame, index) { - var otherFrame = framesB[index]; - mergedFrames.push(pskl.utils.FrameUtils.merge([otherFrame, frame])); - }); - var mergedLayer = pskl.model.Layer.fromFrames(layerA.getName(), mergedFrames); - return mergedLayer; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.utils.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.utils.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.utils.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.utils.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.TooltipFormatter = {}; - - - ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) { - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : helpText, - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - MAX_FPS : 'MAX_FPS', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'MAX_FPS' : 24, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function(){ - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var workers = {}; - - ns.WorkerUtils = { - createWorker : function (worker, workerId) { - if (!workers[workerId]) { - var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")]; - var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here - workers[workerId] = window.URL.createObjectURL(blob); - } - - return new Worker(workers[workerId]); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function (){}; - error = error || function (){}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function(e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function(e) { - error(e, this); - }; - - return xhr; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var step_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - step_callback = callback.step; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - if (!flat) { - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - } - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.size() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.size = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels())); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Palette = function (id, name, colors) { - this.id = id; - this.name = name; - this.colors = colors; - }; - - ns.Palette.fromObject = function (paletteObj) { - var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); - return new ns.Palette(paletteObj.id, paletteObj.name, colors); - }; - - ns.Palette.prototype.getColors = function () { - return this.colors; - }; - - ns.Palette.prototype.setColors = function (colors) { - this.colors = colors; - }; - - ns.Palette.prototype.get = function (index) { - return this.colors[index]; - }; - - ns.Palette.prototype.set = function (index, color) { - this.colors[index] = color; - }; - - ns.Palette.prototype.add = function (color) { - this.colors.push(color); - }; - - ns.Palette.prototype.size = function () { - return this.colors.length; - }; - - ns.Palette.prototype.removeAt = function (index) { - this.colors.splice(index, 1); - }; - - ns.Palette.prototype.move = function (oldIndex, newIndex) { - this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].size() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.addLayerAt = function (layer, index) { - this.layers.splice(index, 0, layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classList - */ - ns.FrameRenderer = function (container, renderingOptions, classList) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classList = classList || []; - this.classList.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.utils.CanvasUtils.clear(this.canvas); - pskl.utils.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.utils.CanvasUtils.createCanvas(width, height, this.classList); - pskl.utils.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) { - var cellSize = this.zoom; - - x = x * cellSize; - y = y * cellSize; - - x = x - this.offset.x * cellSize; - y = y - this.offset.y * cellSize; - - x = x + this.margin.x; - y = y + this.margin.y; - - var containerOffset = this.container.offset(); - x = x + containerOffset.left; - y = y + containerOffset.top; - - return { - x : x + (cellSize/2), - y : y + (cellSize/2) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - var w = 1; - while (color === frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width || this.canvas.height*this.zoom < this.displayCanvas.height) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, width); - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (renderer, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - this.renderer = renderer; - this.add(this.renderer); - - this.hash = ''; - }; - - ns.OnionSkinRenderer.createInContainer = function (container, renderingOptions, piskelController) { - // Do not use CachedFrameRenderers here, caching is performed in the render method - var renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ['onion-skin-canvas']); - return new ns.OnionSkinRenderer(renderer, piskelController); - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var frames = this.getOnionFrames_(); - var hash = this.computeHash_(frames); - if (this.hash != hash) { - this.hash = hash; - this.clear(); - if (frames.length > 0) { - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.getOnionFrames_ = function () { - var frames = []; - - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var layer = this.piskelController.getCurrentLayer(); - - var previousIndex = currentFrameIndex - 1; - var previousFrame = layer.getFrameAt(previousIndex); - if (previousFrame) { - frames.push(previousFrame); - } - - var nextIndex = currentFrameIndex + 1; - var nextFrame = layer.getFrameAt(nextIndex); - if (nextFrame) { - frames.push(nextFrame); - } - - return frames; - }; - - ns.OnionSkinRenderer.prototype.computeHash_ = function (frames) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - return [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join('-'); - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.hash = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - var containerEl = container.get(0); - var containerDocument = containerEl.ownerDocument; - this.displayContainer = containerDocument.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classList) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classList); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - - for(var x = 0, width = this.frame.getWidth(); x < width; x++) { - for(var y = 0, height = this.frame.getHeight(); y < height; y++) { - var color = this.frame.getPixel(x, y); - var w = 1; - while (color === this.frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.utils.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, width); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * previewController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.previewController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.size(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.mergeDownLayerAt = function (index) { - var layer = this.getLayerByIndex(index); - var downLayer = this.getLayerByIndex(index-1); - if (layer && downLayer) { - var mergedLayer = pskl.utils.LayerUtils.mergeLayers(layer, downLayer); - this.removeLayerAt(index); - this.piskel.addLayerAt(mergedLayer, index); - this.removeLayerAt(index-1); - this.selectLayer(mergedLayer); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.removeLayerAt(currentLayerIndex); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - // DECORATED WITH RESET - this.resetWrap_('setCurrentFrameIndex'); - this.resetWrap_('selectNextFrame'); - this.resetWrap_('selectPreviousFrame'); - this.resetWrap_('setCurrentLayerIndex'); - this.resetWrap_('selectLayer'); - // DECORATED WITH SAVE, NO RESET - this.saveWrap_('renameLayerAt', false); - // DECORATED WITH SAVE, WITH RESET - this.saveWrap_('removeCurrentLayer', true); - this.saveWrap_('addFrame', true); - this.saveWrap_('addFrameAtCurrentIndex', true); - this.saveWrap_('addFrameAt', true); - this.saveWrap_('removeFrameAt', true); - this.saveWrap_('duplicateCurrentFrame', true); - this.saveWrap_('duplicateFrameAt', true); - this.saveWrap_('moveFrame', true); - this.saveWrap_('createLayer', true); - this.saveWrap_('mergeDownLayerAt', true); - this.saveWrap_('moveLayerUp', true); - this.saveWrap_('moveLayerDown', true); - this.saveWrap_('removeCurrentLayer', true); - - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.resetWrap_ = function (methodName) { - this[methodName] = function () { - this.piskelController[methodName].apply(this.piskelController, arguments); - $.publish(Events.PISKEL_RESET); - }; - }; - - ns.PublicPiskelController.prototype.saveWrap_ = function (methodName, reset) { - this[methodName] = reset ? function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - $.publish(Events.PISKEL_RESET); - } : function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - }; - }; - - ns.PublicPiskelController.prototype.getStateInfo_ = function () { - var stateInfo = { - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - return stateInfo; - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args, stateInfo) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : { - fn : fn, - args : args - }, - state : stateInfo - }); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - this.dragHandler = new ns.drawing.DragHandler(this); - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = pskl.rendering.OnionSkinRenderer.createInContainer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChange_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(function () { - this.afterWindowResize_(); - this.resetZoom_(); - }.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isIE11) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChange_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - $.publish(Events.MOUSE_EVENT, [event, this]); - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - - this.isClicked = true; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - this.dragHandler.startDrag(event.clientX, event.clientY); - } else { - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - $.publish(Events.TOOL_PRESSED); - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.getSpriteCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - if(this.currentMouseButton_ == Constants.MIDDLE_BUTTON) { - this.dragHandler.updateDrag(x, y); - } else { - $.publish(Events.MOUSE_EVENT, [event, this]); - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - } else { - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - // Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40 - var delta; - if (pskl.utils.UserAgent.isChrome) { - delta = event.wheelDeltaY; - } else if (pskl.utils.UserAgent.isIE11) { - delta = event.wheelDelta; - } else if (pskl.utils.UserAgent.isFirefox) { - delta = -40 * event.deltaY; - } - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - if(this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (this.dragHandler.isDragging()) { - this.dragHandler.stopDrag(); - } else if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) { - return this.renderer.reverseCoordinates(spriteX, spriteY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.getAvailableHeight_(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.getAvailableWidth_(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.getOffset = function () { - return this.compositeRenderer.getOffset(); - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.drawing'); - - /** - * Multiplier applied between the mouse movement and viewport movement - * @type {Number} - */ - var MULTIPLIER = 2; - - /** - * Dedicated handler to drag the drawing canvas using the mouse - * Will store the initial coordinates as well as the status of the drag - * @param {DrawingController} drawingController - */ - ns.DragHandler = function (drawingController) { - this.drawingController = drawingController; - - this.isDragging_ = false; - this.updateOrigin_(-1, -1); - }; - - /** - * Initialize a drag session. - * @param {Number} x : x coordinate of the mouse event that initiated the drag - * @param {Number} y : y coordinate of the mouse event that initiated the drag - */ - ns.DragHandler.prototype.startDrag = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - }; - - /** - * Update the drag status - * @param {Number} x : x coordinate of the mouse event that triggered the update - * @param {Number} y : y coordinate of the mouse event that triggered the update - */ - ns.DragHandler.prototype.updateDrag = function (x, y) { - var currentOffset = this.drawingController.getOffset(); - var offset = this.calculateOffset_(x, y); - if (currentOffset.y !== offset.y || currentOffset.x !== offset.x) { - this.isDragging_ = true; - this.drawingController.setOffset(offset.x, offset.y); - - // retrieve the updated coordinates after moving the sprite - // and store them as the new drag origin - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - } - }; - - /** - * Stop the drag session - */ - ns.DragHandler.prototype.stopDrag = function () { - this.isDragging_ = false; - this.origin = null; - }; - - /** - * Will return true if the drag handler effectively MOVED the offset - * during the current drag session - */ - ns.DragHandler.prototype.isDragging = function () { - return this.isDragging_; - }; - - ns.DragHandler.prototype.calculateOffset_ = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - var currentOffset = this.drawingController.getOffset(); - - var offset = { - x : currentOffset.x - MULTIPLIER * (coords.x - this.origin.x), - y : currentOffset.y - MULTIPLIER * (coords.y - this.origin.y) - }; - - return offset; - }; - - ns.DragHandler.prototype.updateOrigin_ = function (x, y) { - this.origin = this.origin || {}; - this.origin.x = x; - this.origin.y = y; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.FramesListController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.FramesListController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.FramesListController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.FramesListController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.FramesListController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.FramesListController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.FramesListController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.FramesListController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.FramesListController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.FramesListController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.FramesListController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - var height = this.zoom * this.piskelController.getCurrentFrame().getHeight(); - var horizontalMargin = (Constants.PREVIEW_FILM_SIZE - height) / 2; - canvasContainer.style.marginTop = horizontalMargin + 'px'; - - var width = this.zoom * this.piskelController.getCurrentFrame().getWidth(); - var verticalMargin = (Constants.PREVIEW_FILM_SIZE - width) / 2; - canvasContainer.style.marginLeft = verticalMargin + 'px'; - canvasContainer.style.marginRight = verticalMargin + 'px'; - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.FramesListController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.FramesListController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.FramesListController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.utils.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.FramesListController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var frameSize = Math.max(frame.getHeight(), frame.getWidth()); - - return Constants.PREVIEW_FILM_SIZE/frameSize; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - this.updateButtonStatus_(); - }; - - ns.LayersListController.prototype.updateButtonStatus_ = function () { - var layers = this.piskelController.getLayers(); - var currentLayer = this.piskelController.getCurrentLayer(); - var index = this.piskelController.getCurrentLayerIndex(); - - var isLast = index === 0; - var isOnly = layers.length === 1; - var isFirst = index === layers.length - 1; - - this.toggleButtonDisabledState_('up', isFirst); - this.toggleButtonDisabledState_('down', isLast); - this.toggleButtonDisabledState_('merge', isLast); - this.toggleButtonDisabledState_('delete', isOnly); - }; - - ns.LayersListController.prototype.toggleButtonDisabledState_ = function (buttonAction, isDisabled) { - var button = document.querySelector('.layers-button[data-action="'+buttonAction+'"]'); - if (isDisabled) { - button.setAttribute('disabled', 'disabled'); - } else { - button.removeAttribute('disabled'); - } - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } - }; - - ns.LayersListController.prototype.renameCurrentLayer_ = function () { - var layer = this.piskelController.getCurrentLayer(); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.mergeDownCurrentLayer_ = function () { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.mergeDownLayerAt(index); - this.renderLayerList_(); - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } else if (action == 'merge') { - this.mergeDownCurrentLayer_(); - } else if (action == 'edit') { - this.renameCurrentLayer_(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - ns.PopupPreviewController = function (piskelController) { - this.piskelController = piskelController; - this.popup = null; - this.renderer = null; - this.renderFlag = false; - }; - - ns.PopupPreviewController.prototype.init = function () { - pskl.utils.Event.addEventListener(window, 'unload', this.onMainWindowUnload_, this); - }; - - ns.PopupPreviewController.prototype.isOpen = function () { - return !!this.popup; - }; - - ns.PopupPreviewController.prototype.open = function () { - if (!this.isOpen()) { - this.popup = window.open('popup-preview.html', '', 'width=320,height=320'); - } - }; - - ns.PopupPreviewController.prototype.onPopupLoaded = function () { - pskl.utils.Event.addEventListener(this.popup, 'resize', this.onWindowResize_, this); - pskl.utils.Event.addEventListener(this.popup, 'unload', this.onPopupClosed_, this); - var container = this.popup.document.querySelector('.preview-container'); - this.renderer = new pskl.rendering.frame.TiledFrameRenderer($(container)); - this.updateZoom_(); - this.renderFlag = true; - }; - - - ns.PopupPreviewController.prototype.render = function (frame) { - if (this.isOpen() && this.renderer) { - this.renderer.render(frame); - this.renderFlag = false; - } - }; - - ns.PopupPreviewController.prototype.onWindowResize_ = function (frame) { - this.updateZoom_(); - this.renderFlag = true; - }; - - ns.PopupPreviewController.prototype.updateZoom_ = function () { - var documentElement = this.popup.document.documentElement; - var wZoom = documentElement.clientWidth / this.piskelController.getWidth(); - var hZoom = documentElement.clientHeight / this.piskelController.getHeight(); - var zoom = Math.min(wZoom, hZoom); - - this.renderer.setZoom(zoom); - - var height = this.piskelController.getHeight() * zoom; - var width = this.piskelController.getWidth() * zoom; - - var container = this.popup.document.querySelector('.preview-container'); - container.style.height = height + 'px'; - container.style.width = width + 'px'; - - var horizontalMargin = (documentElement.clientHeight - height) / 2; - container.style.marginTop = horizontalMargin + 'px'; - container.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (documentElement.clientWidth - width) / 2; - container.style.marginLeft = verticalMargin + 'px'; - container.style.marginRight = verticalMargin + 'px'; - }; - - ns.PopupPreviewController.prototype.onPopupClosed_ = function () { - var popup = this.popup; - console.log(popup); - this.popup = null; - }; - - ns.PopupPreviewController.prototype.onMainWindowUnload_ = function () { - if (this.isOpen()) { - this.popup.close(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.PreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.renderFlag = true; - - this.fpsRangeInput = $('#preview-fps'); - this.fpsCounterDisplay = $('#display-fps'); - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - this.popupPreviewController = new ns.PopupPreviewController(piskelController); - }; - - ns.PreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this)); - document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.utils.Event.addEventListener('.open-popup-preview-button', 'click', this.onOpenPopupPreviewClick_, this); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - $.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true)); - $.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true)); - - this.popupPreviewController.init(); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - this.updateMaxFPS_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.onOpenPopupPreviewClick_ = function () { - this.popupPreviewController.open(); - }; - - ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else if (name == pskl.UserSettings.MAX_FPS) { - this.updateMaxFPS_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.PreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.PreviewController.prototype.updateMaxFPS_ = function () { - var maxFps = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.fpsRangeInput.get(0).setAttribute('max', maxFps); - this.setFPS(Math.min(this.fps, maxFps)); - }; - - ns.PreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.PreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.PreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.PreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt(this.fpsRangeInput[0].value, 10)); - - }; - - ns.PreviewController.prototype.setFPS = function (fps) { - if (typeof fps === 'number') { - this.fps = fps; - // reset - this.fpsRangeInput.get(0).value = 0; - // set proper value - this.fpsRangeInput.get(0).value = this.fps; - this.fpsRangeInput.blur(); - this.fpsCounterDisplay.html(this.fps + ' FPS'); - } - }; - - ns.PreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.PreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = this.getNextIndex_(delta); - if (this.shoudlRender_() || this.currentIndex != index) { - this.currentIndex = index; - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - this.renderFlag = false; - - this.popupPreviewController.render(frame); - } - }; - - ns.PreviewController.prototype.getNextIndex_ = function (delta) { - if (this.fps === 0) { - return this.piskelController.getCurrentFrameIndex(); - } else { - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (!this.piskelController.hasFrameAt(index)) { - this.elapsedTime = 0; - index = 0; - } - return index; - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.PreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var hZoom = PREVIEW_SIZE / frame.getHeight(), - wZoom = PREVIEW_SIZE / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.PreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + 'px'; - containerEl.style.width = width + 'px'; - - var horizontalMargin = (PREVIEW_SIZE - height) / 2; - containerEl.style.marginTop = horizontalMargin + 'px'; - containerEl.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (PREVIEW_SIZE - width) / 2; - containerEl.style.marginLeft = verticalMargin + 'px'; - containerEl.style.marginRight = verticalMargin + 'px'; - }; - - ns.PreviewController.prototype.setRenderFlag_ = function (bool) { - this.renderFlag = bool; - }; - - ns.PreviewController.prototype.shoudlRender_ = function () { - return this.renderFlag || this.popupPreviewController.renderFlag; - }; - - ns.PreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, previewController, drawingController, container) { - this.piskelController = piskelController; - this.previewController = previewController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - this.isVisible = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.minimapEl = document.createElement('DIV'); - this.minimapEl.className = 'minimap-crop-frame'; - this.minimapEl.style.display = 'none'; - $(this.container).append(this.minimapEl); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var verticalRatio = this.getVerticalRatio_(); - var horizontalRatio = this.getHorizontalRatio_(); - if (verticalRatio > 1 || horizontalRatio > 1) { - this.displayMinimap_(); - } else { - this.hideMinimap_(); - } - }; - - ns.MinimapController.prototype.displayMinimap_ = function () { - var minimapSize = this.getMinimapSize_(); - var previewSize = this.getPreviewSize_(); - - var containerHeight = this.container.height(); - var containerWidth = this.container.width(); - - // offset(x, y) in frame pixels - var offset = this.drawingController.getRenderer().getOffset(); - - // the preview is centered in a square container - // if the sprite is not a square, a margin is needed on the appropriate coordinate - // before adding the offset coming from the drawing area - var leftMargin = (containerWidth - Math.max(minimapSize.width, previewSize.width))/2; - var leftOffset = offset.x * this.previewController.getZoom(); - var left = leftMargin + leftOffset; - - var topMargin = (containerHeight - Math.max(minimapSize.height, previewSize.height))/2; - var topOffset = offset.y * this.previewController.getZoom(); - var top = topMargin + topOffset; - - this.minimapEl.style.display = 'block'; - this.minimapEl.style.width = Math.min(minimapSize.width, containerWidth) + 'px'; - this.minimapEl.style.height = Math.min(minimapSize.height, containerHeight) + 'px'; - this.minimapEl.style.left = Math.max(0, left) + 'px'; - this.minimapEl.style.top = Math.max(0, top) + 'px'; - - this.isVisible = true; - }; - - ns.MinimapController.prototype.getMinimapSize_ = function () { - // Calculate the ratio to translate drawing area sizes to animated preview sizes - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var animatedPreviewZoom = this.previewController.getZoom(); - var ratio = drawingAreaZoom / animatedPreviewZoom; - - var displaySize = this.drawingController.getRenderer().getDisplaySize(); - var minimapWidth = displaySize.width / ratio; - var minimapHeight = displaySize.height / ratio; - - return { - width : minimapWidth, - height: minimapHeight - }; - }; - - ns.MinimapController.prototype.getPreviewSize_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewWidth = frame.getWidth() * this.previewController.getZoom(); - var previewHeight = frame.getHeight() * this.previewController.getZoom(); - - return { - width : previewWidth, - height: previewHeight - }; - }; - - ns.MinimapController.prototype.hideMinimap_ = function () { - this.minimapEl.style.display = 'none'; - this.isVisible = false; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isVisible && this.isClicked) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.previewController.getCoordinates(x, y); - - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / this.getHorizontalRatio_(); - var height = frameHeight / this.getVerticalRatio_(); - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getVerticalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalHeight = frame.getHeight() * drawingAreaZoom; - var frameDisplayHeight = this.drawingController.getRenderer().getDisplaySize().height; - - return frameTotalHeight / frameDisplayHeight; - }; - - ns.MinimapController.prototype.getHorizontalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalWidth = frame.getWidth() * drawingAreaZoom; - var frameDisplayWidth = this.drawingController.getRenderer().getDisplaySize().width; - - return frameTotalWidth / frameDisplayWidth; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()), - toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()), - toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()), - toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()), - toDescriptor('move', 'M', new pskl.tools.drawing.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - - $.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.tools.drawing.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) { - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - return pskl.utils.Array.find(this.tools, function (tool) { - return tool.instance.toolId == toolId; - }); - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var html = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - html += this.toolIconRenderer.render(tool.instance, tool.shortcut); - } - $('#tools-container').html(html); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteService = pskl.app.paletteService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - - var createPaletteButton_ = document.querySelector('.create-palette-button'); - var editPaletteButton_ = document.querySelector('.edit-palette-button'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - editPaletteButton_.addEventListener('click', this.onEditPaletteClick_.bind(this)); - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - - pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this)); - pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this)); - - this.fillPaletteList(); - this.updateFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = this.paletteService.getPalettes(); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.colorPaletteSelect_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - - var colors = this.getSelectedPaletteColors_(); - - if (colors.length > 0) { - var html = colors.map(function (color, index) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - } else { - this.colorListContainer_.innerHTML = pskl.utils.Template.get('palettes-list-no-colors-partial'); - } - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var palette = this.getSelectedPalette_(); - if (palette) { - colors = palette.getColors(); - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.getSelectedPalette_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - return this.paletteService.getPaletteById(paletteId); - }; - - ns.PalettesListController.prototype.selectNextColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() + 1); - }; - - ns.PalettesListController.prototype.selectPreviousColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() - 1); - }; - - ns.PalettesListController.prototype.getCurrentColorIndex_ = function () { - var currentIndex = 0; - var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME); - if (selectedColor) { - currentIndex = parseInt(selectedColor.dataset.colorIndex, 10); - } - return currentIndex; - }; - - ns.PalettesListController.prototype.selectColor_ = function (index) { - var colors = this.getSelectedPaletteColors_(); - var color = colors[index]; - if (color) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } - }; - - ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.SELECTED_PALETTE) { - this.updateFromUserSettings(); - } - }; - - ns.PalettesListController.prototype.updateFromUserSettings = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - this.fillColorListContainer(); - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - this.selectPalette(paletteId); - this.colorPaletteSelect_.blur(); - }; - - ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); - }; - - ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : paletteId - }); - }; - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.updateFromUserSettings(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.ProgressBarController = function () { - this.template = pskl.utils.Template.get('progress-bar-template'); - this.progressBar = null; - this.progressBarStatus = null; - - this.showProgressTimer_ = 0; - }; - - ns.ProgressBarController.prototype.init = function () { - $.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this)); - $.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this)); - $.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this)); - }; - - ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) { - this.removeProgressBar_(); - this.showProgressTimer_ = window.setTimeout(this.onTimerExpired_.bind(this, progressInfo), 300); - }; - - ns.ProgressBarController.prototype.onTimerExpired_ = function (progressInfo) { - var progressBarHtml = pskl.utils.Template.replace(this.template, { - name : progressInfo.name, - status : 0 - }); - - var progressBarEl = pskl.utils.Template.createFromHTML(progressBarHtml); - document.body.appendChild(progressBarEl); - - this.progressBar = document.querySelector('.progress-bar'); - this.progressBarStatus = document.querySelector('.progress-bar-status'); - }; - - ns.ProgressBarController.prototype.updateProgress_ = function (event, progressInfo) { - if (this.progressBar && this.progressBarStatus) { - var progress = progressInfo.progress; - var width = this.progressBar.offsetWidth; - var progressWidth = width - ((progress * width) / 100); - this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; - this.progressBarStatus.innerHTML = progress + '%'; - } - }; - - ns.ProgressBarController.prototype.hideProgress_ = function (event, progressInfo) { - if (this.showProgressTimer_) { - window.clearTimeout(this.showProgressTimer_); - } - this.removeProgressBar_(); - }; - - ns.ProgressBarController.prototype.removeProgressBar_ = function () { - var progressBarContainer = document.querySelector('.progress-bar-container'); - if (progressBarContainer) { - progressBarContainer.parentNode.removeChild(progressBarContainer); - this.progressBar = null; - this.progressBarStatus = null; - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - - message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this)); - if (messageInfo.behavior) { - messageInfo.behavior(message); - } - - if (messageInfo.hideDelay) { - window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.TransformationsController = function () { - - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('flip', '', new pskl.tools.transform.Flip()), - toDescriptor('rotate', '', new pskl.tools.transform.Rotate()), - toDescriptor('clone', '', new pskl.tools.transform.Clone()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - ns.TransformationsController.prototype.init = function () { - var container = document.querySelector('.transformations-container'); - this.toolsContainer = container.querySelector('.tools-wrapper'); - container.addEventListener('click', this.onTransformationClick.bind(this)); - this.createToolsDom_(); - }; - - - ns.TransformationsController.prototype.onTransformationClick = function (evt) { - var toolId = evt.target.dataset.toolId; - this.tools.forEach(function (tool) { - if (tool.instance.toolId === toolId) { - tool.instance.apply(evt); - } - }.bind(this)); - }; - - ns.TransformationsController.prototype.createToolsDom_ = function() { - var html = this.tools.reduce(function (p, tool) { - return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left'); - }.bind(this), ''); - this.toolsContainer.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - ns.AbstractSettingController = function () {}; - - ns.AbstractSettingController.prototype.addEventListener = function (el, type, callback) { - pskl.utils.Event.addEventListener(el, type, callback, this); - }; - - - ns.AbstractSettingController.prototype.destroy = function () { - pskl.utils.Event.removeAllEventListeners(this); - this.nullifyDomReferences_(); - }; - - ns.AbstractSettingController.prototype.nullifyDomReferences_ = function () { - for (var key in this) { - if (this.hasOwnProperty(key)) { - var isHTMLElement = this[key] && this[key].nodeName; - if (isHTMLElement) { - this[key] = null; - } - } - } - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - pskl.utils.inherit(ns.ApplicationSettingsController, pskl.controller.settings.AbstractSettingController); - - ns.ApplicationSettingsController.prototype.init = function() { - this.backgroundContainer = document.querySelector('.background-picker-wrapper'); - this.addEventListener(this.backgroundContainer, 'click', this.onBackgroundClick_); - - // Highlight selected background : - var background = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - var selectedBackground = this.backgroundContainer.querySelector('[data-background=' + background + ']'); - if (selectedBackground) { - selectedBackground.classList.add('selected'); - } - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - var gridSelect = document.querySelector('.grid-width-select'); - var selectedOption = gridSelect.querySelector('option[value="'+gridWidth+'"]'); - if (selectedOption) { - selectedOption.setAttribute('selected', 'selected'); - } - - this.addEventListener(gridSelect, 'change', this.onGridWidthChange_); - - // Tiled preview - var tiledPreview = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var tiledPreviewCheckbox = document.querySelector('.tiled-preview-checkbox'); - if (tiledPreview) { - tiledPreviewCheckbox.setAttribute('checked', tiledPreview); - } - this.addEventListener(tiledPreviewCheckbox, 'change', this.onTiledPreviewChange_); - - // Max FPS - var maxFpsInput = document.querySelector('.max-fps-input'); - maxFpsInput.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.addEventListener(maxFpsInput, 'change', this.onMaxFpsChange_); - - // Form - this.applicationSettingsForm = document.querySelector('[name="application-settings-form"]'); - this.addEventListener(this.applicationSettingsForm, 'submit', this.onFormSubmit_); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange_ = function (evt) { - var width = parseInt(evt.target.value, 10); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, width); - }; - - ns.ApplicationSettingsController.prototype.onTiledPreviewChange_ = function (evt) { - pskl.UserSettings.set(pskl.UserSettings.TILED_PREVIEW, evt.currentTarget.checked); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick_ = function (evt) { - var target = evt.target; - var background = target.dataset.background; - if (background) { - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, background); - var selected = this.backgroundContainer.querySelector('.selected'); - if (selected) { - selected.classList.remove('selected'); - } - target.classList.add('selected'); - } - }; - - ns.ApplicationSettingsController.prototype.onMaxFpsChange_ = function (evt) { - var target = evt.target; - var fps = parseInt(target.value, 10); - if (fps && !isNaN(fps)) { - pskl.UserSettings.set(pskl.UserSettings.MAX_FPS, fps); - } else { - target.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - } - }; - - ns.ApplicationSettingsController.prototype.onFormSubmit_ = function (evt) { - evt.preventDefault(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController); - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = document.querySelector(".gif-upload-button"); - this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_); - - this.downloadButton = document.querySelector(".gif-download-button"); - this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.uploadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.downloadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.downloadImageData_ = function (imageData) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.GifExportController.prototype.uploadImageData_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this), this.onImageUploadFailed_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.onImageUploadFailed_ = function (event, xhr) { - if (xhr.status === 500) { - $.publish(Events.SHOW_NOTIFICATION, [{ - "content": "Upload failed : " + xhr.responseText, - "hideDelay" : 5000 - }]); - } - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 5, - quality: 1, - width: this.piskelController.getWidth() * zoom, - height: this.piskelController.getHeight() * zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Building animated GIF ...'}]); - gif.on('progress', function(percentage) { - $.publish(Events.UPDATE_PROGRESS, [{"progress": (percentage*100).toFixed(1)}]); - }.bind(this)); - - gif.on('finished', function(blob) { - $.publish(Events.HIDE_PROGRESS); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController); - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelector('.png-export-preview'); - this.pngFilePrefixInput = document.getElementById('zip-prefix-name'); - this.pngFilePrefixInput.value = 'sprite_'; - - var downloadButton = document.querySelector(".png-download-button"); - this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_); - - var zipButton = document.querySelector(".zip-generate-button"); - this.addEventListener(zipButton, 'click', this.onZipButtonClick_); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var basename = this.pngFilePrefixInput.value; - var filename = basename + (i+1) + ".png"; - zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - var OPTION_CLASSNAME = 'resize-origin-option'; - - ns.AnchorWidget = function (container) { - this.container = container; - this.disabled = false; - pskl.utils.Event.addEventListener(this.container, 'click', this.onResizeOriginClick_, this); - }; - - ns.AnchorWidget.ORIGIN = { - TOPLEFT : 'TOPLEFT', - TOP : 'TOP', - TOPRIGHT : 'TOPRIGHT', - MIDDLELEFT : 'MIDDLELEFT', - MIDDLE : 'MIDDLE', - MIDDLERIGHT : 'MIDDLERIGHT', - BOTTOMLEFT : 'BOTTOMLEFT', - BOTTOM : 'BOTTOM', - BOTTOMRIGHT : 'BOTTOMRIGHT' - }; - - ns.AnchorWidget.prototype.destroy = function (evt) { - pskl.utils.Event.removeAllEventListeners(this); - this.container = null; - }; - - ns.AnchorWidget.prototype.onResizeOriginClick_ = function (evt) { - var origin = evt.target.dataset.origin; - if (origin && ns.AnchorWidget.ORIGIN[origin] && !this.disabled) { - this.setOrigin(origin); - } - }; - - ns.AnchorWidget.prototype.setOrigin = function (origin) { - this.origin = origin; - var previous = document.querySelector('.'+OPTION_CLASSNAME+'.selected'); - if (previous) { - previous.classList.remove('selected'); - } - - var selected = document.querySelector('.'+OPTION_CLASSNAME+'[data-origin="' + origin + '"]'); - if (selected) { - selected.classList.add('selected'); - this.refreshNeighbors_(selected); - } - }; - - ns.AnchorWidget.prototype.getOrigin = function () { - return this.origin; - }; - - ns.AnchorWidget.prototype.disable = function () { - this.disabled = true; - this.container.classList.add('transition'); - this.container.classList.add('disabled'); - }; - - ns.AnchorWidget.prototype.enable = function () { - this.disabled = false; - this.container.classList.remove('disabled'); - window.setTimeout(this.container.classList.remove.bind(this.container.classList, 'transition'), 250); - }; - - ns.AnchorWidget.prototype.refreshNeighbors_ = function (selected) { - var options = document.querySelectorAll('.'+OPTION_CLASSNAME); - for (var i = 0 ; i < options.length ; i++) { - options[i].removeAttribute('data-neighbor'); - } - - var selectedIndex = Array.prototype.indexOf.call(options, selected); - - this.setNeighborhood_(options[selectedIndex - 1], 'left'); - this.setNeighborhood_(options[selectedIndex + 1], 'right'); - this.setNeighborhood_(options[selectedIndex - 3], 'top'); - this.setNeighborhood_(options[selectedIndex + 3], 'bottom'); - }; - - ns.AnchorWidget.prototype.setNeighborhood_ = function (el, neighborhood) { - var origin = this.origin.toLowerCase(); - var isNeighborhoodValid = origin.indexOf(neighborhood) === -1; - if (isNeighborhoodValid) { - el.setAttribute('data-neighbor', neighborhood); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.ResizeController = function (piskelController) { - this.piskelController = piskelController; - - this.container = document.querySelector('.resize-canvas'); - - var anchorWidgetContainer = this.container.querySelector('.resize-origin-container'); - this.anchorWidget = new ns.AnchorWidget(anchorWidgetContainer); - }; - - pskl.utils.inherit(ns.ResizeController, pskl.controller.settings.AbstractSettingController); - - ns.ResizeController.prototype.init = function () { - this.widthInput = this.container.querySelector('[name="resize-width"]'); - this.heightInput = this.container.querySelector('[name="resize-height"]'); - - this.widthInput.value = this.piskelController.getWidth(); - this.heightInput.value = this.piskelController.getHeight(); - - this.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_); - this.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_); - - this.resizeForm = this.container.querySelector('form'); - this.addEventListener(this.resizeForm, 'submit', this.onResizeFormSubmit_); - - this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox'); - this.addEventListener(this.resizeContentCheckbox, 'change', this.onResizeContentChange_); - - this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox'); - this.addEventListener(this.maintainRatioCheckbox, 'change', this.onMaintainRatioChange_); - - this.anchorWidget.setOrigin(ns.AnchorWidget.ORIGIN.TOPLEFT); - this.lastInput = this.widthInput; - }; - - ns.ResizeController.prototype.destroy = function () { - this.anchorWidget.destroy(); - this.superclass.destroy.call(this); - }; - - ns.ResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.preventDefault(); - - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - - ns.ResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.ResizeController.prototype.onResizeContentChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.anchorWidget.disable(); - } else { - this.anchorWidget.enable(); - } - }; - - ns.ResizeController.prototype.onMaintainRatioChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.synchronizeSizeInputs_(this.lastInput); - } - }; - - ns.ResizeController.prototype.onSizeInputKeyUp_ = function (evt) { - var target = evt.target; - if (this.maintainRatioCheckbox.checked) { - this.synchronizeSizeInputs_(target); - } - this.lastInput = target; - }; - - /** - * Based on the value of the provided sizeInput (considered as emitter) - * update the value of the other sizeInput to match the current width/height ratio - * @param {HTMLElement} origin either widthInput or heightInput - */ - ns.ResizeController.prototype.synchronizeSizeInputs_ = function (sizeInput) { - var value = parseInt(sizeInput.value, 10); - if (isNaN(value)) { - value = 0; - } - - var height = this.piskelController.getHeight(), - width = this.piskelController.getWidth(); - - if (sizeInput === this.widthInput) { - this.heightInput.value = Math.round(value * height/width); - } else if (sizeInput === this.heightInput) { - this.widthInput.value = Math.round(value * width/height); - } - }; - - /***********************/ - /* RESIZE LOGIC */ - /***********************/ - - ns.ResizeController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.widthInput.value, 10); - var height = parseInt(this.heightInput.value, 10); - if (this.resizeContentCheckbox.checked) { - return pskl.utils.FrameUtils.resize(frame, width, height, false); - } else { - var resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - var translated = this.translateCoordinates_(x, y, frame, resizedFrame); - if (resizedFrame.containsPixel(translated.x, translated.y)) { - resizedFrame.setPixel(translated.x, translated.y, color); - } - }.bind(this)); - - return resizedFrame; - } - }; - - ns.ResizeController.prototype.translateCoordinates_ = function (x, y, frame, resizedFrame) { - return { - x : this.translateX_(x, frame.width, resizedFrame.width), - y : this.translateY_(y, frame.height, resizedFrame.height) - }; - }; - - ns.ResizeController.prototype.translateX_ = function (x, width, resizedWidth) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('LEFT') != -1) { - return x; - } else if (origin.indexOf('RIGHT') != -1) { - return x - (width - resizedWidth); - } else { - return x - Math.round((width - resizedWidth)/2); - } - }; - - ns.ResizeController.prototype.translateY_ = function (y, height, resizedHeight) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('TOP') != -1) { - return y; - } else if (origin.indexOf('BOTTOM') != -1) { - return y - (height - resizedHeight); - } else { - return y - Math.round((height - resizedHeight)/2); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.SaveController, pskl.controller.settings.AbstractSettingController); - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - // timestamp used to generate unique name when saving as .piskel - this.timestamp = new Date(); - - // Only available in app-engine mode - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = document.querySelector('#save-online-status'); - this.saveFileStatus = document.querySelector('#save-file-status'); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = document.querySelector('#save-description'); - this.descriptionInput.value = descriptor.description; - - this.isPublicCheckbox = document.querySelector('input[name=save-public-checkbox]'); - if (descriptor.isPublic) { - this.isPublicCheckbox.setAttribute('checked', true); - } - - this.addEventListener('#save-file-button', 'click', this.saveFile_); - this.addEventListener('#save-browser-button', 'click', this.saveLocal_); - - this.saveOnlineButton = document.querySelector('#save-online-button'); - this.addEventListener(this.saveOnlineButton, 'click', this.saveOnline_); - - this.addEventListener('form[name=save-form]', 'submit', this.onSaveFormSubmit_); - - this.nameInput = document.querySelector('#save-name'); - this.nameInput.value = descriptor.name; - this.addEventListener(this.nameInput, 'keyup', this.updateLocalStatusFilename_); - - if (pskl.app.isLoggedIn()) { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-online-status-partial'); - } else { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-please-login-partial'); - var container = document.querySelector('.setting-save-section'); - container.classList.add('anonymous'); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.innerHTML = pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - }); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.innerHTML = 'Saving ...'; - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.value; - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.value; - }; - - ns.SaveController.prototype.isPublic_ = function () { - return !!this.isPublicCheckbox.checked; - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.innerHTML = ''; - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.ImportController, pskl.controller.settings.AbstractSettingController); - - ns.ImportController.prototype.init = function () { - this.hiddenFileInput = document.querySelector('[name="file-upload-input"]'); - this.addEventListener(this.hiddenFileInput, 'change', this.onFileUploadChange_); - - this.hiddenOpenPiskelInput = document.querySelector('[name="open-piskel-input"]'); - this.addEventListener(this.hiddenOpenPiskelInput, 'change', this.onOpenPiskelChange_); - - this.addEventListener('.browse-local-button', 'click', this.onBrowseLocalClick_); - this.addEventListener('.file-input-button', 'click', this.onFileInputClick_); - this.addEventListener('.open-piskel-button', 'click', this.onOpenPiskelClick_); - - this.initRestoreSession_(); - }; - - ns.ImportController.prototype.initRestoreSession_ = function () { - var previousSessionContainer = document.querySelector('.previous-session'); - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var previousSessionTemplate_ = pskl.utils.Template.get('previous-session-info-template'); - var date = pskl.utils.DateUtils.format(previousInfo.date, '{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}'); - previousSessionContainer.innerHTML = pskl.utils.Template.replace(previousSessionTemplate_, { - name : previousInfo.name, - date : date - }); - this.addEventListener('.restore-session-button', 'click', this.onRestorePreviousSessionClick_); - } else { - previousSessionContainer.innerHTML = 'No piskel backup was found on this browser.'; - } - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - var files = this.hiddenOpenPiskelInput.files; - if (files.length == 1) { - this.openPiskelFile_(files[0]); - } - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function (file) { - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - this.closeDrawer_(); - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.resize.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.exportimage.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - if (this.currentController && this.currentController.destroy) { - this.currentController.destroy(); - } - - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - - this.currentSetting = setting; - this.currentController = new settings[setting].controller(this.piskelController); - this.currentController.init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - this.destroy(); - $.publish(Events.DIALOG_HIDE); - }; - - ns.AbstractDialogController.prototype.setTitle = function (title) { - var dialogTitle = document.querySelector('.dialog-title'); - if (dialogTitle) { - dialogTitle.innerText = title; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteController = function (piskelController) { - this.paletteService = pskl.app.paletteService; - this.paletteImportService = pskl.app.paletteImportService; - }; - - pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - - ns.CreatePaletteController.prototype.init = function (paletteId) { - this.superclass.init.call(this); - - this.hiddenFileInput = document.querySelector('.create-palette-import-input'); - this.nameInput = document.querySelector('input[name="palette-name"]'); - - var buttonsContainer = document.querySelector('.create-palette-actions'); - var deleteButton = document.querySelector('.create-palette-delete'); - var downloadButton = document.querySelector('.create-palette-download-button'); - var importFileButton = document.querySelector('.create-palette-import-button'); - - this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); - this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - - buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this)); - downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this)); - importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); - - var colorsListContainer = document.querySelector('.colors-container'); - this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer); - - var palette; - var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID; - if (paletteId && !isCurrentColorsPalette) { - importFileButton.style.display = 'none'; - this.setTitle('Edit Palette'); - - var paletteObject = this.paletteService.getPaletteById(paletteId); - palette = pskl.model.Palette.fromObject(paletteObject); - } else { - downloadButton.style.display = 'none'; - deleteButton.style.display = 'none'; - this.setTitle('Create Palette'); - - var uuid = pskl.utils.Uuid.generate(); - if (isCurrentColorsPalette) { - palette = new pskl.model.Palette(uuid, 'Current colors clone', this.getCurrentColors_()); - } else { - palette = new pskl.model.Palette(uuid, 'New palette', []); - } - } - - this.setPalette_(palette); - }; - - ns.CreatePaletteController.prototype.getCurrentColors_ = function () { - var palette = this.paletteService.getPaletteById(Constants.CURRENT_COLORS_PALETTE_ID); - return palette.getColors(); - }; - - ns.CreatePaletteController.prototype.setPalette_ = function (palette) { - this.palette = palette; - this.nameInput.value = pskl.utils.unescapeHtml(palette.name); - this.colorsListWidget.setColors(palette.getColors()); - }; - - ns.CreatePaletteController.prototype.destroy = function () { - this.colorsListWidget.destroy(); - this.nameInput = null; - }; - - ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) { - var target = evt.target; - if (target.dataset.action === 'submit') { - this.saveAndSelectPalette_(); - } else if (target.dataset.action === 'cancel') { - this.closeDialog(); - } else if (target.dataset.action === 'delete') { - this.deletePalette_(); - } - }; - - ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function () { - this.palette.setColors(this.colorsListWidget.getColors()); - this.paletteService.savePalette(this.palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, this.palette.id); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.deletePalette_ = function () { - if (window.confirm('Are you sure you want to delete palette ' + this.palette.name)) { - this.paletteService.deletePaletteById(this.palette.id); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, Constants.CURRENT_COLORS_PALETTE_ID); - this.closeDialog(); - } - }; - - ns.CreatePaletteController.prototype.onDownloadButtonClick_ = function () { - var paletteWriter = new pskl.service.palette.PaletteGplWriter(this.palette); - var paletteAsString = paletteWriter.write(); - - pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.palette.name + '.gpl'); - }.bind(this), "application/json"); - }; - - ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { - this.hiddenFileInput.click(); - }; - - ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - this.paletteImportService.read(files[0], this.setPalette_.bind(this), this.displayErrorMessage_.bind(this)); - } - }; - - ns.CreatePaletteController.prototype.displayErrorMessage_ = function (message) { - message = "Could not import palette : " + message; - $.publish(Events.SHOW_NOTIFICATION, [{"content": message}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { - this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (image) { - this.importedImage_ = image; - - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.utils.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'create-palette' : { - template : 'templates/dialogs/create-palette.html', - controller : ns.CreatePaletteController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette')); - - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.classList.add(dialogId); - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - var DEFAULT_COLOR = '#000000'; - - ns.ColorsList = function (container) { - this.selectedIndex = -1; - this.palette = new pskl.model.Palette('tmp', 'tmp', []); - this.container = container; - - this.colorsList = this.container.querySelector('.colors-list'); - this.colorPreviewEl = this.container.querySelector('.color-preview'); - - $(container).sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onColorDrop_.bind(this), - items: '.create-palette-color' - }); - - this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - - var colorPickerContainer = container.querySelector('.color-picker-container'); - this.hslRgbColorPicker = new pskl.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); - this.hslRgbColorPicker.init(); - }; - - ns.ColorsList.prototype.setColors = function (colors) { - if (colors.length === 0) { - colors.push(DEFAULT_COLOR); - } - - this.palette.setColors(colors); - - this.selectColor_(0); - this.refresh_(); - }; - - ns.ColorsList.prototype.getColors = function () { - return this.palette.getColors(); - }; - - ns.ColorsList.prototype.destroy = function () { - this.hslRgbColorPicker.destroy(); - this.container = null; - this.colorsList = null; - this.colorPreviewEl = null; - }; - - /** - * Lightweight refresh only changing the color of one element of the palette color list - */ - ns.ColorsList.prototype.refreshColorElement_ = function (index) { - var color = this.palette.get(this.selectedIndex); - var element = document.querySelector('[data-palette-index="'+index+'"]'); - if (element) { - element.style.background = color; - element.classList.toggle('light-color', this.isLight_(color)); - } - }; - - ns.ColorsList.prototype.onColorContainerClick_ = function (evt) { - var target = evt.target; - if (target.classList.contains('create-palette-color')) { - this.onPaletteColorClick_(evt, target); - } else if (target.classList.contains('create-palette-new-color')) { - this.onNewColorClick_(evt, target); - } else if (target.classList.contains('create-palette-remove-color')) { - this.onRemoveColorClick_(evt, target); - } - this.refresh_(); - }; - - ns.ColorsList.prototype.onColorUpdated_ = function (color) { - var rgbColor = color.toRgbString(); - this.colorPreviewEl.style.background = rgbColor; - if (this.palette) { - this.palette.set(this.selectedIndex, rgbColor); - this.refreshColorElement_(this.selectedIndex); - } - }; - - ns.ColorsList.prototype.onPaletteColorClick_ = function (evt, target) { - var index = parseInt(target.dataset.paletteIndex,10); - this.selectColor_(index); - }; - - ns.ColorsList.prototype.onRemoveColorClick_ = function (evt, target) { - var colorElement = target.parentNode; - var index = parseInt(colorElement.dataset.paletteIndex,10); - this.removeColor_(index); - }; - - ns.ColorsList.prototype.onNewColorClick_ = function (evt, target) { - var newColor = this.palette.get(this.selectedIndex) || '#000000'; - this.palette.add(newColor); - this.selectColor_(this.palette.size()-1); - }; - - ns.ColorsList.prototype.refresh_ = function () { - var html = ""; - var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.getColors(); - - colors.forEach(function (color, index) { - var isSelected = (index === this.selectedIndex); - - html += pskl.utils.Template.replace(tpl, { - 'color':color, index:index, - ':selected':isSelected, - ':light-color':this.isLight_(color) - }); - }.bind(this)); - - html += '
      • +
      • '; - - this.colorsList.innerHTML = html; - }; - - ns.ColorsList.prototype.selectColor_ = function (index) { - this.selectedIndex = index; - this.hslRgbColorPicker.setColor(this.palette.get(index)); - }; - - ns.ColorsList.prototype.removeColor_ = function (index) { - this.palette.removeAt(index); - this.refresh_(); - }; - - ns.ColorsList.prototype.isLight_ = function (color) { - var rgb = window.tinycolor(color).toRgb(); - return rgb.r+rgb.b+rgb.g > 128*3; - }; - - ns.ColorsList.prototype.onColorDrop_ = function (evt, drop) { - var colorElement = drop.item.get(0); - - var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); - var newIndex = $('.create-palette-color').index(drop.item); - this.palette.move(oldIndex, newIndex); - - this.selectedIndex = newIndex; - - this.refresh_(); - }; -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { - this.container = container; - this.colorUpdatedCallback = colorUpdatedCallback; - - this.tinyColor = null; - this.hsvColor = null; - this.rgbColor = null; - - this.lastInputTimestamp_ = 0; - }; - - ns.HslRgbColorPicker.prototype.init = function () { - var isChromeOrFirefox = pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isFirefox; - var changeEvent = isChromeOrFirefox ? 'input' : 'change'; - this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this)); - this.container.addEventListener('keydown', this.onKeydown_.bind(this)); - this.container.addEventListener('focusout', this.onBlur_.bind(this)); - - this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); - - $(this.spectrumEl).spectrum({ - flat: true, - showButtons: false, - move : this.setColor.bind(this), - change : this.setColor.bind(this) - }); - - this.setColor("#000000"); - }; - - ns.HslRgbColorPicker.prototype.destroy = function () { - this.container = null; - this.spectrumEl = null; - }; - - ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) { - var target = evt.target; - if (target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = target.value; - - this.updateColor_(value, model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.onKeydown_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - - if (model === 'rgb' || model === 'hsv') { - var increment = this.getIncrement_(evt); - if (increment) { - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - this.updateColor_(value + increment, model, dimension); - } - } - } - }; - - ns.HslRgbColorPicker.prototype.getIncrement_ = function (evt) { - var increment = 0; - var key = pskl.service.keyboard.KeycodeTranslator.toChar(evt.keyCode); - if (key === 'up') { - increment = 1; - } else if (key === 'down') { - increment = -1; - } - - if (evt.shiftKey) { - increment = increment * 5; - } - - return increment; - }; - - ns.HslRgbColorPicker.prototype.updateColor_ = function (inputValue, model, dimension) { - var value = this.toModelValue_(inputValue, model, dimension); - if (model === 'hsv' || model === 'rgb') { - if (!isNaN(value)) { - var color = this.getColor_(model); - color[dimension] = this.normalizeDimension_(value, dimension); - this.setColor(color); - } - } else if (model === 'hex') { - if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) { - this.setColor(value); - } - } - }; - - ns.HslRgbColorPicker.prototype.onBlur_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - target.value = this.toInputValue_(model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - this.rgbColor = this.tinyColor.toRgb(); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.colorUpdatedCallback(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.HslRgbColorPicker.prototype.updateInputs = function () { - var inputs = this.container.querySelectorAll('input'); - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - var value = this.toInputValue_(model, dimension); - if (input.value != value) { - input.value = value; - } - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.HslRgbColorPicker.prototype.toInputValue_ = function (model, dimension) { - var value; - - if (model === 'rgb' || model === 'hsv') { - var color = this.getColor_(model); - value = color[dimension]; - - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - value = Math.round(value); - } else if (model === 'hex') { - value = this.tinyColor.toHexString(true); - } - - return value; - }; - - ns.HslRgbColorPicker.prototype.toModelValue_ = function (value, model, dimension) { - var modelValue; - - if (model === 'rgb' || model === 'hsv') { - modelValue = parseInt(value, 10); - if (dimension === 'v' || dimension === 's') { - modelValue = modelValue/100; - } - } else if (model === 'hex') { - modelValue = value; - } - - return modelValue; - }; - - ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { - var isTinyColor = typeof color == 'object' && color.hasOwnProperty('_tc_id'); - if (isTinyColor) { - return color; - } else { - return window.tinycolor(pskl.utils.copy(color)); - } - }; - - ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : this.normalizeDimension_(color.h, 'h'), - s : this.normalizeDimension_(color.s, 's'), - v : this.normalizeDimension_(color.v, 'v') - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) { - var range = this.getDimensionRange_(dimension); - return Math.max(range[0], Math.min(range[1], value)); - }; - - /** - * Update background colors for range inputs - */ - ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - var colors = this.getSliderBackgroundColors_(model, dimension); - slider.style.backgroundImage = "linear-gradient(to right, " + colors.start + " 0, " + colors.end + " 100%)"; - } - }; - - ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) { - var color = this.getColor_(model); - var start = pskl.utils.copy(color); - var end = pskl.utils.copy(color); - - var range = this.getDimensionRange_(dimension); - start[dimension] = range[0]; - end[dimension] = range[1]; - - return { - start : window.tinycolor(start).toRgbString(), - end : window.tinycolor(end).toRgbString() - }; - }; - - ns.HslRgbColorPicker.prototype.getDimensionRange_ = function (d) { - if (d === 'h') { - return [0, 359]; - } else if (d === 's' || d === 'v') { - return [0, 1]; - } else if (d === 'r' || d === 'g' || d === 'b') { - return [0, 255]; - } - }; - - ns.HslRgbColorPicker.prototype.getColor_ = function (model) { - var color; - if (model === 'hsv') { - color = this.hsvColor; - } else if (model === 'rgb'){ - color = this.rgbColor; - } - return color; - }; - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var data = { - framesheet : this.piskelController.serialize(), - fps : this.piskelController.getFPS(), - name : descriptor.name, - description : descriptor.description, - frames : this.piskelController.getFrameCount(), - first_frame_as_png : pskl.app.getFirstFrameAsPng(), - framesheet_as_png : pskl.app.getFramesheetAsPng() - }; - - if (descriptor.isPublic) { - data['public'] = true; - } - - var success = function () { - callbacks.success(); - callbacks.after(); - }; - - var error = function (response) { - callbacks.error(response.status); - callbacks.after(); - }; - - pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - // 1 minute = 1000 * 60 - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - this.savePiskel_('prev', previousPiskel, previousInfo); - } - - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - this.savePiskel_('next', this.piskelController.serialize(), JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(previousInfo.fps); - }); - }; - - ns.BackupService.prototype.savePiskel_ = function (type, piskel, info) { - try { - window.localStorage.setItem('bkp.' + type +'.piskel', piskel); - window.localStorage.setItem('bkp.' + type +'.info', info); - } catch (e) { - console.error('Could not save piskel backup in localStorage.', e); - } - }; -})(); - - - - -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.HistoryService = function (piskelController, shortcutService, deserializer) { - this.piskelController = piskelController || pskl.app.piskelController; - this.shortcutService = shortcutService || pskl.app.shortcutService; - this.deserializer = deserializer || pskl.utils.serialization.Deserializer; - - this.stateQueue = []; - this.currentIndex = -1; - - this.lastLoadState = -1; - }; - - // Force to save a state as a SNAPSHOT - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - - // Default save state - ns.HistoryService.REPLAY = 'REPLAY'; - - // Period (in number of state saved) between two snapshots - ns.HistoryService.SNAPSHOT_PERIOD = 50; - - // Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming) - ns.HistoryService.LOAD_STATE_INTERVAL = 50; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); - - this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, action) { - this.saveState(action); - }; - - ns.HistoryService.prototype.saveState = function (action) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : action, - frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex, - layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = action.type === ns.HistoryService.SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0; - if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - } - - this.stateQueue.push(state); - $.publish(Events.HISTORY_STATE_SAVED); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - // Should only do this when going backwards - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - $.publish(Events.HISTORY_STATE_LOADED); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service.color'); - - var LOW_SAT = 0.1; - var LOW_LUM = 0.1; - var HI_LUM = 0.9; - - - var HUE_STEP = 36; - var HUE_BAGS = 10; - var HUE_BOUNDS = []; - for (var i = 0 ; i < HUE_BAGS ; i++) { - HUE_BOUNDS.push(i * HUE_STEP); - } - - ns.ColorSorter = function () { - this.colorsHslMap_ = {}; - }; - - ns.ColorSorter.prototype.sort = function (colors) { - this.colorsHslMap_ = {}; - - colors.forEach(function (color) { - this.colorsHslMap_[color] = window.tinycolor(color).toHsl(); - }.bind(this)); - - // sort by most frequent color - var darkColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l <= LOW_LUM; - }.bind(this)); - - var brightColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l >= HI_LUM; - }.bind(this)); - - var desaturatedColors = colors.filter(function (c) { - return brightColors.indexOf(c) === -1 && darkColors.indexOf(c) === -1; - }).filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.s <= LOW_SAT; - }.bind(this)); - - darkColors = this.sortOnHslProperty_(darkColors, 'l'); - brightColors = this.sortOnHslProperty_(brightColors, 'l'); - desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); - - var sortedColors = darkColors.concat(brightColors, desaturatedColors); - - var regularColors = colors.filter(function (c) { - return sortedColors.indexOf(c) === -1; - }); - - var regularColorsBags = HUE_BOUNDS.map(function (hue) { - var bagColors = regularColors.filter(function (color) { - var hsl = this.colorsHslMap_[color]; - return (hsl.h >= hue && hsl.h < hue + HUE_STEP); - }.bind(this)); - - return this.sortRegularColors_(bagColors); - }.bind(this)); - - return Array.prototype.concat.apply(sortedColors, regularColorsBags); - }; - - ns.ColorSorter.prototype.sortRegularColors_ = function (colors) { - var sortedColors = colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - var hDiff = Math.abs(hsl1.h - hsl2.h); - var sDiff = Math.abs(hsl1.s - hsl2.s); - var lDiff = Math.abs(hsl1.l - hsl2.l); - if (hDiff < 10) { - if (sDiff > lDiff) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - return this.compareValues_(hsl1.l, hsl2.l); - } - } else { - return this.compareValues_(hsl1.h, hsl2.h); - } - }.bind(this)); - - return sortedColors; - }; - - ns.ColorSorter.prototype.sortOnHslProperty_ = function (colors, property) { - return colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - return this.compareValues_(hsl1[property], hsl2[property]); - }.bind(this)); - }; - - ns.ColorSorter.prototype.compareValues_ = function (v1, v2) { - if (v1 > v2) { - return 1; - } else if (v1 < v2) { - return -1; - } - return 0; - }; - -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.CurrentColorsPalette = function () { - this.name = 'Current colors'; - this.id = Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsPalette.prototype.getColors = function () { - return pskl.app.currentColorsService.getCurrentColors(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteService = function () { - this.dynamicPalettes = []; - this.localStorageService = window.localStorage; - }; - - ns.PaletteService.prototype.getPalettes = function () { - var palettesString = this.localStorageService.getItem('piskel.palettes'); - var palettes = JSON.parse(palettesString) || []; - palettes = palettes.map(function (palette) { - return pskl.model.Palette.fromObject(palette); - }); - - return this.dynamicPalettes.concat(palettes); - }; - - ns.PaletteService.prototype.getPaletteById = function (paletteId) { - var palettes = this.getPalettes(); - return this.findPaletteInArray_(paletteId, palettes); - }; - - ns.PaletteService.prototype.savePalette = function (palette) { - var palettes = this.getPalettes(); - var existingPalette = this.findPaletteInArray_(palette.id, palettes); - if (existingPalette) { - var currentIndex = palettes.indexOf(existingPalette); - palettes.splice(currentIndex, 1, palette); - } else { - palettes.push(palette); - } - - this.savePalettes_(palettes); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteService.prototype.addDynamicPalette = function (palette) { - this.dynamicPalettes.push(palette); - }; - - ns.PaletteService.prototype.deletePaletteById = function (id) { - var palettes = this.getPalettes(); - var filteredPalettes = palettes.filter(function (palette) { - return palette.id !== id; - }); - - this.savePalettes_(filteredPalettes); - }; - - ns.PaletteService.prototype.savePalettes_ = function (palettes) { - palettes = palettes.filter(function (palette) { - return this.dynamicPalettes.indexOf(palette) === -1; - }.bind(this)); - this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteGplWriter = function (palette) { - this.palette = palette; - }; - - ns.PaletteGplWriter.prototype.write = function () { - var lines = []; - lines.push('GIMP Palette'); - lines.push('Name: ' + this.palette.name); - lines.push('Columns: 0'); - lines.push('#'); - this.palette.getColors().forEach(function (color) { - lines.push(this.writeColorLine(color)); - }.bind(this)); - lines.push('\r\n'); - - return lines.join('\r\n'); - }; - - ns.PaletteGplWriter.prototype.writeColorLine = function (color) { - var tinycolor = window.tinycolor(color); - var rgb = tinycolor.toRgb(); - var strBuffer = []; - strBuffer.push(this.padString(rgb.r, 3)); - strBuffer.push(this.padString(rgb.g, 3)); - strBuffer.push(this.padString(rgb.b, 3)); - strBuffer.push('Untitled'); - - return strBuffer.join(' '); - }; - - ns.PaletteGplWriter.prototype.padString = function (str, size) { - str = str.toString(); - var pad = (new Array(1+size-str.length)).join(' '); - return pad + str; - }; - -})(); -;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.AbstractPaletteFileReader = function (file, onSuccess, onError, colorLineRegexp) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - this.colorLineRegexp = colorLineRegexp; - }; - - ns.AbstractPaletteFileReader.prototype.extractColorFromLine = Constants.ABSTRACT_FUNCTION; - - ns.AbstractPaletteFileReader.prototype.read = function () { - pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this)); - }; - - ns.AbstractPaletteFileReader.prototype.onFileLoaded_ = function (content) { - var text = pskl.utils.Base64.toText(content); - var lines = text.match(/[^\r\n]+/g); - - var colorLines = lines.filter(function (l) { - return this.colorLineRegexp.test(l); - }.bind(this)); - - var colors = colorLines.map(this.extractColorFromLine.bind(this)); - - if (colors.length) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name, colors); - this.onSuccess(palette); - } else { - this.onError(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/; - var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; - - ns.PaletteGplReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteGplReader, ns.AbstractPaletteFileReader); - - ns.PaletteGplReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = window.tinycolor({ - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10) - }); - - return color.toRgbString(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.PaletteImageReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - - this.colorSorter_ = new pskl.service.color.ColorSorter(); - }; - - ns.PaletteImageReader.prototype.read = function () { - pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this)); - }; - - ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) { - var imageProcessor = new pskl.worker.ImageProcessor(image, - this.onWorkerSuccess_.bind(this), - this.onWorkerStep_.bind(this), - this.onWorkerError_.bind(this)); - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]); - - imageProcessor.process(); - }; - - ns.PaletteImageReader.prototype.onWorkerSuccess_ = function (event) { - var data = event.data; - var colorsMap = data.colorsMap; - - var colors = Object.keys(colorsMap); - - if (colors.length > 200) { - this.onError('Too many colors : ' + colors.length); - } else { - var uuid = pskl.utils.Uuid.generate(); - var sortedColors = this.colorSorter_.sort(colors); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', sortedColors); - - this.onSuccess(palette); - } - $.publish(Events.HIDE_PROGRESS); - }; - - ns.PaletteImageReader.prototype.onWorkerStep_ = function (event) { - var progress = event.data.progress; - $.publish(Events.UPDATE_PROGRESS, [{"progress": progress}]); - }; - - ns.PaletteImageReader.prototype.onWorkerError_ = function (event) { - $.publish(Events.HIDE_PROGRESS); - this.onError('Unable to process the image : ' + event.data.message); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})/; - - ns.PalettePalReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PalettePalReader, ns.AbstractPaletteFileReader); - - ns.PalettePalReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = 'rgb(' + matches[1] + ',' + matches[2] + ',' + matches[3] + ')'; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/; - - ns.PaletteTxtReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteTxtReader, ns.AbstractPaletteFileReader); - - ns.PaletteTxtReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = "#" + matches[1] + matches[2] + matches[3]; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var fileReaders = { - 'gpl' : ns.reader.PaletteGplReader, - 'pal' : ns.reader.PalettePalReader, - 'txt' : ns.reader.PaletteTxtReader, - 'img' : ns.reader.PaletteImageReader - }; - - ns.PaletteImportService = function () {}; - - ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader = this.getReader_(file, onSuccess, onError); - if (reader) { - reader.read(); - } else { - throw 'Could not find reader for file : ' + file.name; - } - }; - - ns.PaletteImportService.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.PaletteImportService.prototype.getReader_ = function (file, onSuccess, onError) { - var readerClass = this.getReaderClass_(file); - if (readerClass) { - return new readerClass(file, onSuccess, onError); - } else { - return null; - } - }; - - ns.PaletteImportService.prototype.getReaderClass_ = function (file) { - var readerClass; - if (this.isImage_(file)) { - readerClass = fileReaders.img; - } else { - var extension = this.getExtension_(file); - readerClass = fileReaders[extension]; - } - return readerClass; - }; - - ns.PaletteImportService.prototype.getExtension_ = function (file) { - var parts = file.name.split('.'); - var extension = parts[parts.length-1]; - return extension.toLowerCase(); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.addShortcuts = function (keys, callback) { - keys.forEach(function (key) { - this.addShortcut(key, callback); - }.bind(this)); - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+", - 188 : "<", - 190 : ">" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Create a Palette'), - this.toDescriptor_('</>', 'Select previous/next palette color'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} success success callback. 1st argument will be the uploaded image URL - * @param {Function} error error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, success, error) { - var data = { - data : imageData - }; - - var wrappedSuccess = function (response) { - success(Constants.IMAGE_SERVICE_GET_URL + response.responseText); - }; - - pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - // cache of current colors by history state - this.cache = {}; - this.currentColors = []; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); - - this.colorSorter = new pskl.service.color.ColorSorter(); - this.paletteService = pskl.app.paletteService; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.HISTORY_STATE_SAVED, this.updateCurrentColors_.bind(this)); - $.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.setCurrentColors = function (colors) { - var historyIndex = pskl.app.historyService.currentIndex; - this.cache[historyIndex] = colors; - if (colors.join('') !== this.currentColors.join('')) { - this.currentColors = colors; - $.publish(Events.CURRENT_COLORS_UPDATED); - } - }; - - ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); - - return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsService.prototype.loadColorsFromCache_ = function () { - var historyIndex = pskl.app.historyService.currentIndex; - var colors = this.cache[historyIndex]; - if (colors) { - this.setCurrentColors(colors); - } - }; - - ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = true; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - var currentColors = this.colorSorter.sort(colorsArray); - - this.setCurrentColors(currentColors); - }; - - ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexString_(color); - frameColors[hexColor] = true; - }.bind(this)); - return frameColors; - }; - - ns.CurrentColorsService.prototype.toHexString_ = function (color) { - if (color === Constants.TRANSPARENT_COLOR) { - return color; - } else { - color = color.replace(/\s/g, ''); - var hexRe = (/^#([a-f0-9]{3}){1,2}$/i); - var rgbRe = (/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i); - if (hexRe.test(color)) { - return color.toUpperCase(); - } else if (rgbRe.test(color)) { - var exec = rgbRe.exec(color); - return pskl.utils.rgbToHex(exec[1] * 1, exec[2] * 1, exec[3] * 1); - } else { - console.error('Could not convert color to hex : ', color); - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - var isPiskel = /\.piskel$/i.test(file.name); - var isPalette = /\.(gpl|txt|pal)$/i.test(file.name); - if (isImage) { - this.readImageFile_(file); - } else if (isPiskel) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } else if (isPalette) { - pskl.app.paletteImportService.read(file, this.onPaletteLoaded_.bind(this)); - } - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.onPaletteLoaded_ = function (palette) { - pskl.app.paletteService.savePalette(palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.Tool = function () { - this.toolId = "tool"; - this.helpText = "Abstract tool"; - this.tooltipDescriptors = []; - }; - - ns.Tool.prototype.getHelpText = function() { - return this.helpText; - }; - - ns.Tool.prototype.getId = function() { - return this.toolId; - }; -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.IconMarkupRenderer = function () {}; - - ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) { - tooltipPosition = tooltipPosition || 'right'; - shortcut = shortcut ? '(' + shortcut + ')' : ''; - var tpl = pskl.utils.Template.get('drawingTool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : ['tool-icon', tool.toolId].join(' '), - toolid : tool.toolId, - title : this.getTooltipText(tool, shortcut), - tooltipposition : tooltipPosition - }); - }; - - ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) { - var descriptors = tool.tooltipDescriptors; - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : tool.getHelpText(), - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.IconMarkupRenderer.prototype.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.IconMarkupRenderer.prototype.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;/** - * @provide pskl.tools.drawing.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.BaseTool = function() { - pskl.tool.Tool.call(this); - this.toolId = "tool-base"; - }; - - pskl.utils.inherit(ns.BaseTool, pskl.tools.Tool); - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.tools.drawing'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [coords.col, coords.row]); - this.raiseSaveStateEvent({ - col : coords.col, - row : coords.row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.tools.drawing.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i 0) { - var node = this; - for (var i = 0 ; i < parts.length ; i++) { - if (!node[parts[i]]) { - node[parts[i]] = {}; - } - node = node[parts[i]]; - } - } - }); - var script = createNamespace + ""; - script = script.replace(/function \(\) \{/,"").replace(/\}[^}]*$/, ""); - script = "var name = '" + name + "';" + script; - - this.runScript(script); - }; - - ns.ImageProcessor.prototype.onWorkerMessage = function (event) { - if (event.data.type === 'STEP') { - this.onStep(event); - } else if (event.data.type === 'SUCCESS') { - this.onSuccess(event); - this.worker.terminate(); - } else if (event.data.type === 'ERROR') { - this.onError(event); - this.worker.terminate(); - } - }; - - ns.ImageProcessor.prototype.importAll__ = function (classToImport, classpath) { - this.createNamespace(classpath); - for (var key in classToImport) { - if (classToImport.hasOwnProperty(key)) { - this.addMethod(classToImport[key], classpath + '.' + key); - } - } - }; - - ns.ImageProcessor.prototype.addMethod__ = function (method, name) { - this.runScript(name + "=" + method); - }; - - ns.ImageProcessor.prototype.runScript__ = function (script) { - this.worker.postMessage({ - type : 'RUN_SCRIPT', - script : this.getScriptAsUrl(script) - }); - }; - - ns.ImageProcessor.prototype.getScriptAsUrl__ = function (script) { - var blob = new Blob([script], {type: "application/javascript"}); // pass a useful mime type here - return window.URL.createObjectURL(blob); - }; -})(); - - - -;/** - * @require Constants - * @require Events - */ -(function () { - var ns = $.namespace("pskl"); - /** - * Main application controller - */ - ns.app = { - - init : function () { - /** - * When started from APP Engine, appEngineToken_ (Boolean) should be set on window.pskl - */ - this.isAppEngineVersion = !!pskl.appEngineToken_; - - this.shortcutService = new pskl.service.keyboard.ShortcutService(); - this.shortcutService.init(); - - var size = { - height : Constants.DEFAULT.HEIGHT, - width : Constants.DEFAULT.WIDTH - }; - - var descriptor = new pskl.model.piskel.Descriptor('New Piskel', ''); - var piskel = new pskl.model.Piskel(size.width, size.height, descriptor); - - var layer = new pskl.model.Layer("Layer 1"); - var frame = new pskl.model.Frame(size.width, size.height); - - layer.addFrame(frame); - piskel.addLayer(layer); - - this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel); - this.corePiskelController.init(); - - this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); - this.piskelController.init(); - - this.paletteImportService = new pskl.service.palette.PaletteImportService(); - this.paletteService = new pskl.service.palette.PaletteService(); - this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette()); - - this.paletteController = new pskl.controller.PaletteController(); - this.paletteController.init(); - - this.currentColorsService = new pskl.service.CurrentColorsService(this.piskelController); - this.currentColorsService.init(); - - this.palettesListController = new pskl.controller.PalettesListController(this.paletteController, this.currentColorsService); - this.palettesListController.init(); - - this.cursorCoordinatesController = new pskl.controller.CursorCoordinatesController(this.piskelController); - this.cursorCoordinatesController.init(); - - this.drawingController = new pskl.controller.DrawingController(this.piskelController, this.paletteController, $('#drawing-canvas-container')); - this.drawingController.init(); - - this.previewController = new pskl.controller.preview.PreviewController(this.piskelController, $('#animated-preview-canvas-container')); - this.previewController.init(); - - this.minimapController = new pskl.controller.MinimapController(this.piskelController, this.previewController, this.drawingController, $('.minimap-container')); - this.minimapController.init(); - - this.framesListController = new pskl.controller.FramesListController(this.piskelController, $('#preview-list')); - this.framesListController.init(); - - this.layersListController = new pskl.controller.LayersListController(this.piskelController); - this.layersListController.init(); - - this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController); - this.settingsController.init(); - - this.dialogsController = new pskl.controller.dialogs.DialogsController(this.piskelController); - this.dialogsController.init(); - - this.toolController = new pskl.controller.ToolController(); - this.toolController.init(); - - this.selectionManager = new pskl.selection.SelectionManager(this.piskelController); - this.selectionManager.init(); - - this.historyService = new pskl.service.HistoryService(this.corePiskelController); - this.historyService.init(); - - this.notificationController = new pskl.controller.NotificationController(); - this.notificationController.init(); - - this.transformationsController = new pskl.controller.TransformationsController(); - this.transformationsController.init(); - - this.progressBarController = new pskl.controller.ProgressBarController(); - this.progressBarController.init(); - - this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController(); - this.canvasBackgroundController.init(); - - this.localStorageService = new pskl.service.LocalStorageService(this.piskelController); - this.localStorageService.init(); - - this.imageUploadService = new pskl.service.ImageUploadService(); - this.imageUploadService.init(); - - this.cheatsheetService = new pskl.service.keyboard.CheatsheetService(); - this.cheatsheetService.init(); - - this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController); - this.savedStatusService.init(); - - this.backupService = new pskl.service.BackupService(this.piskelController); - this.backupService.init(); - - this.beforeUnloadService = new pskl.service.BeforeUnloadService(this.piskelController); - this.beforeUnloadService.init(); - - this.fileDropperService = new pskl.service.FileDropperService(this.piskelController, $('#drawing-canvas-container').get(0)); - this.fileDropperService.init(); - - if (this.isAppEngineVersion) { - this.storageService = new pskl.service.AppEngineStorageService(this.piskelController); - } else { - this.storageService = new pskl.service.GithubStorageService(this.piskelController); - } - this.storageService.init(); - - var drawingLoop = new pskl.rendering.DrawingLoop(); - drawingLoop.addCallback(this.render, this); - drawingLoop.start(); - - this.initTooltips_(); - - var piskelData = this.getPiskelInitData_(); - if (piskelData && piskelData.piskel) { - this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); - } - - if (pskl.devtools) { - pskl.devtools.init(); - } - }, - - loadPiskel_ : function (serializedPiskel, descriptor, fps) { - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }, - - getPiskelInitData_ : function () { - return pskl.appEnginePiskelData_; - }, - - isLoggedIn : function () { - var piskelData = this.getPiskelInitData_(); - return piskelData && piskelData.isLoggedIn; - }, - - initTooltips_ : function () { - $('body').tooltip({ - selector: '[rel=tooltip]' - }); - }, - - render : function (delta) { - this.drawingController.render(delta); - this.previewController.render(delta); - this.framesListController.render(delta); - }, - - getFirstFrameAsPng : function () { - var firstFrame = this.piskelController.getFrameAt(0); - var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); - canvasRenderer.drawTransparentAs('rgba(0,0,0,0)'); - var firstFrameCanvas = canvasRenderer.render(); - return firstFrameCanvas.toDataURL("image/png"); - }, - - getFramesheetAsPng : function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - var framesheetCanvas = renderer.renderAsCanvas(); - return framesheetCanvas.toDataURL("image/png"); - } - }; -})(); - -;(function () { - var flipFrame = function (frame, horizontal, vertical) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - clone.forEachPixel(function (color, x, y) { - if (horizontal) { - x = w-x-1; - } - if (vertical) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - }; - - window.flip = function (horizontal, vertical) { - var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex(); - var layers = pskl.app.piskelController.getLayers(); - layers.forEach(function (layer) { - flipFrame(layer.getFrameAt(currentFrameIndex), horizontal, vertical); - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - window.copyToAll = function () { - var ref = pskl.app.piskelController.getCurrentFrame(); - var layer = pskl.app.piskelController.getCurrentLayer(); - layer.getFrames().forEach(function (frame) { - if (frame !== ref) { - frame.setPixels(ref.getPixels()); - } - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; -})(); \ No newline at end of file diff --git a/js/piskel-packaged-2015-03-02-09-45.js b/js/piskel-packaged-2015-03-02-09-45.js deleted file mode 100644 index 336a1d49..00000000 --- a/js/piskel-packaged-2015-03-02-09-45.js +++ /dev/null @@ -1,24855 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing', - - // SERVICE URLS - APPENGINE_SAVE_URL : 'save', - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - SELECT_TOOL : "SELECT_TOOL", - - TOOL_RELEASED : "TOOL_RELEASED", - TOOL_PRESSED : "TOOL_PRESSED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - HISTORY_STATE_SAVED: "HISTORY_STATE_SAVED", - HISTORY_STATE_LOADED: "HISTORY_STATE_LOADED", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - SHOW_PROGRESS: "SHOW_PROGRESS", - UPDATE_PROGRESS: "UPDATE_PROGRESS", - HIDE_PROGRESS: "HIDE_PROGRESS", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", - - MOUSE_EVENT : "MOUSE_EVENT", - - // Tests - TEST_RECORD_END : "TEST_RECORD_END", - TEST_CASE_END : "TEST_CASE_END", - TEST_SUITE_END : "TEST_SUITE_END" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i": ">", - '"': '"', - "'": ''', - "/": '/' - }; - ns.escapeHtml= function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml= function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], "g"); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Array = { - find : function (array, filterFn) { - var match = null; - array = Array.isArray(array) ? array : []; - var filtered = array.filter(filterFn); - if (filtered.length) { - match = filtered[0]; - } - return match; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/,'')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement('canvas'); - canvas.setAttribute('width', width); - canvas.setAttribute('height', height); - - if (typeof classList == 'string') { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.utils.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.utils.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, false); - }, - - enableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, true); - }, - - setImageSmoothing : function (canvas, smoothing) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = smoothing; - context.mozImageSmoothingEnabled = smoothing; - context.oImageSmoothingEnabled = smoothing; - context.webkitImageSmoothingEnabled = smoothing; - context.msImageSmoothingEnabled = smoothing; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.utils.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || 'png'; - var data = canvas.toDataURL('image/' + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Event = {}; - - ns.Event.addEventListener = function (el, type, callback, scope, args) { - if (typeof el === 'string') { - el = document.querySelector(el); - } - - var listener = { - el : el, - type : type, - callback : callback, - handler : args ? callback.bind(scope, args) : callback.bind(scope) - }; - - scope.__pskl_listeners = scope.__pskl_listeners || []; - scope.__pskl_listeners.push(listener); - el.addEventListener(type, listener.handler); - }; - - ns.Event.removeEventListener = function (el, type, callback, scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - if (listener.callback === callback && listener.el === el && listener.type === type) { - el.removeEventListener(type, listeners[i].handler); - listeners.splice(i, 1); - break; - } - } - } - }; - - ns.Event.removeAllEventListeners = function (scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - listener.el.removeEventListener(listener.type, listener.handler); - } - scope.__pskl_listeners = []; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.FrameTransform = { - VERTICAL : 'vertical', - HORIZONTAL : 'HORIZONTAL', - flip : function (frame, axis) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - clone.forEachPixel(function (color, x, y) { - if (axis === ns.FrameTransform.VERTICAL) { - x = w-x-1; - } else if (axis === ns.FrameTransform.HORIZONTAL) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - return frame; - }, - - CLOCKWISE : 'clockwise', - COUNTERCLOCKWISE : 'counterclockwise', - rotate : function (frame, direction) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - var max = Math.max(w, h); - var xDelta = Math.ceil((max - w)/2); - var yDelta = Math.ceil((max - h)/2); - - frame.forEachPixel(function (color, x, y) { - var _x = x, _y = y; - - // Convert to square coords - x = x + xDelta; - y = y + yDelta; - - // Perform the rotation - var tmpX = x, tmpY = y; - if (direction === ns.FrameTransform.CLOCKWISE) { - x = tmpY; - y = max - 1 - tmpX; - } else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) { - y = tmpX; - x = max - 1 - tmpY; - } - - // Convert the coordinates back to the rectangular grid - x = x - xDelta; - y = y - yDelta; - if (clone.containsPixel(x, y)) { - frame.pixels[_x][_y] = clone.getPixel(x, y); - } else { - frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR; - } - }); - frame.version++; - return frame; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - /** - * Render a Frame object as an image. - * Can optionally scale it (zoom) - * @param {Frame} frame - * @param {Number} zoom - * @return {Image} - */ - toImage : function (frame, zoom) { - zoom = zoom || 1; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }, - - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (color, col, row) { - if (color != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, color); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.utils.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); - }, - - createFromImageData_ : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels__ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba__ : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createLayerFromSpritesheet : function (image, frameCount) { - var width = image.width, - height = image.height, - frameWidth = width / frameCount; - - var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, height); - var context = canvas.getContext('2d'); - - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - context.clearRect(0, 0 , frameWidth, height); - context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); - var frame = pskl.utils.FrameUtils.createFromImage(canvas); - frames.push(frame); - } - return frames; - }, - - mergeLayers : function (layerA, layerB) { - var framesA = layerA.getFrames(); - var framesB = layerB.getFrames(); - var mergedFrames = []; - framesA.forEach(function (frame, index) { - var otherFrame = framesB[index]; - mergedFrames.push(pskl.utils.FrameUtils.merge([otherFrame, frame])); - }); - var mergedLayer = pskl.model.Layer.fromFrames(layerA.getName(), mergedFrames); - return mergedLayer; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.utils.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.utils.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.utils.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.utils.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.TooltipFormatter = {}; - - - ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) { - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : helpText, - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - MAX_FPS : 'MAX_FPS', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'MAX_FPS' : 24, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function(){ - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var workers = {}; - - ns.WorkerUtils = { - createWorker : function (worker, workerId) { - if (!workers[workerId]) { - var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")]; - var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here - workers[workerId] = window.URL.createObjectURL(blob); - } - - return new Worker(workers[workerId]); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function (){}; - error = error || function (){}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function(e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function(e) { - error(e, this); - }; - - return xhr; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var step_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - step_callback = callback.step; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - if (!flat) { - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - } - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.size() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.size = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels())); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Palette = function (id, name, colors) { - this.id = id; - this.name = name; - this.colors = colors; - }; - - ns.Palette.fromObject = function (paletteObj) { - var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); - return new ns.Palette(paletteObj.id, paletteObj.name, colors); - }; - - ns.Palette.prototype.getColors = function () { - return this.colors; - }; - - ns.Palette.prototype.setColors = function (colors) { - this.colors = colors; - }; - - ns.Palette.prototype.get = function (index) { - return this.colors[index]; - }; - - ns.Palette.prototype.set = function (index, color) { - this.colors[index] = color; - }; - - ns.Palette.prototype.add = function (color) { - this.colors.push(color); - }; - - ns.Palette.prototype.size = function () { - return this.colors.length; - }; - - ns.Palette.prototype.removeAt = function (index) { - this.colors.splice(index, 1); - }; - - ns.Palette.prototype.move = function (oldIndex, newIndex) { - this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].size() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.addLayerAt = function (layer, index) { - this.layers.splice(index, 0, layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classList - */ - ns.FrameRenderer = function (container, renderingOptions, classList) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classList = classList || []; - this.classList.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.utils.CanvasUtils.clear(this.canvas); - pskl.utils.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.utils.CanvasUtils.createCanvas(width, height, this.classList); - pskl.utils.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) { - var cellSize = this.zoom; - - x = x * cellSize; - y = y * cellSize; - - x = x - this.offset.x * cellSize; - y = y - this.offset.y * cellSize; - - x = x + this.margin.x; - y = y + this.margin.y; - - var containerOffset = this.container.offset(); - x = x + containerOffset.left; - y = y + containerOffset.top; - - return { - x : x + (cellSize/2), - y : y + (cellSize/2) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - var w = 1; - while (color === frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width || this.canvas.height*this.zoom < this.displayCanvas.height) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, width); - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (renderer, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - this.renderer = renderer; - this.add(this.renderer); - - this.hash = ''; - }; - - ns.OnionSkinRenderer.createInContainer = function (container, renderingOptions, piskelController) { - // Do not use CachedFrameRenderers here, caching is performed in the render method - var renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ['onion-skin-canvas']); - return new ns.OnionSkinRenderer(renderer, piskelController); - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var frames = this.getOnionFrames_(); - var hash = this.computeHash_(frames); - if (this.hash != hash) { - this.hash = hash; - this.clear(); - if (frames.length > 0) { - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.getOnionFrames_ = function () { - var frames = []; - - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var layer = this.piskelController.getCurrentLayer(); - - var previousIndex = currentFrameIndex - 1; - var previousFrame = layer.getFrameAt(previousIndex); - if (previousFrame) { - frames.push(previousFrame); - } - - var nextIndex = currentFrameIndex + 1; - var nextFrame = layer.getFrameAt(nextIndex); - if (nextFrame) { - frames.push(nextFrame); - } - - return frames; - }; - - ns.OnionSkinRenderer.prototype.computeHash_ = function (frames) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - return [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join('-'); - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.hash = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - var containerEl = container.get(0); - var containerDocument = containerEl.ownerDocument; - this.displayContainer = containerDocument.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classList array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classList) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classList); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - - for(var x = 0, width = this.frame.getWidth(); x < width; x++) { - for(var y = 0, height = this.frame.getHeight(); y < height; y++) { - var color = this.frame.getPixel(x, y); - var w = 1; - while (color === this.frame.getPixel(x, y+w)) { - w++; - } - this.renderLine_(color, x, y, w, context); - y = y + w - 1; - } - } - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.utils.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, width); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.utils.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * previewController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.previewController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.size(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.mergeDownLayerAt = function (index) { - var layer = this.getLayerByIndex(index); - var downLayer = this.getLayerByIndex(index-1); - if (layer && downLayer) { - var mergedLayer = pskl.utils.LayerUtils.mergeLayers(layer, downLayer); - this.removeLayerAt(index); - this.piskel.addLayerAt(mergedLayer, index); - this.removeLayerAt(index-1); - this.selectLayer(mergedLayer); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.removeLayerAt(currentLayerIndex); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - // DECORATED WITH RESET - this.resetWrap_('setCurrentFrameIndex'); - this.resetWrap_('selectNextFrame'); - this.resetWrap_('selectPreviousFrame'); - this.resetWrap_('setCurrentLayerIndex'); - this.resetWrap_('selectLayer'); - // DECORATED WITH SAVE, NO RESET - this.saveWrap_('renameLayerAt', false); - // DECORATED WITH SAVE, WITH RESET - this.saveWrap_('removeCurrentLayer', true); - this.saveWrap_('addFrame', true); - this.saveWrap_('addFrameAtCurrentIndex', true); - this.saveWrap_('addFrameAt', true); - this.saveWrap_('removeFrameAt', true); - this.saveWrap_('duplicateCurrentFrame', true); - this.saveWrap_('duplicateFrameAt', true); - this.saveWrap_('moveFrame', true); - this.saveWrap_('createLayer', true); - this.saveWrap_('mergeDownLayerAt', true); - this.saveWrap_('moveLayerUp', true); - this.saveWrap_('moveLayerDown', true); - this.saveWrap_('removeCurrentLayer', true); - - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.resetWrap_ = function (methodName) { - this[methodName] = function () { - this.piskelController[methodName].apply(this.piskelController, arguments); - $.publish(Events.PISKEL_RESET); - }; - }; - - ns.PublicPiskelController.prototype.saveWrap_ = function (methodName, reset) { - this[methodName] = reset ? function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - $.publish(Events.PISKEL_RESET); - } : function () { - var stateInfo = this.getStateInfo_(); - this.piskelController[methodName].apply(this.piskelController, arguments); - this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo); - }; - }; - - ns.PublicPiskelController.prototype.getStateInfo_ = function () { - var stateInfo = { - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - return stateInfo; - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args, stateInfo) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : { - fn : fn, - args : args - }, - state : stateInfo - }); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - this.dragHandler = new ns.drawing.DragHandler(this); - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = pskl.rendering.OnionSkinRenderer.createInContainer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChange_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(function () { - this.afterWindowResize_(); - this.resetZoom_(); - }.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isIE11) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChange_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - $.publish(Events.MOUSE_EVENT, [event, this]); - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - - this.isClicked = true; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - this.dragHandler.startDrag(event.clientX, event.clientY); - } else { - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - $.publish(Events.TOOL_PRESSED); - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.getSpriteCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - if(this.currentMouseButton_ == Constants.MIDDLE_BUTTON) { - this.dragHandler.updateDrag(x, y); - } else { - $.publish(Events.MOUSE_EVENT, [event, this]); - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - } else { - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - // Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40 - var delta; - if (pskl.utils.UserAgent.isChrome) { - delta = event.wheelDeltaY; - } else if (pskl.utils.UserAgent.isIE11) { - delta = event.wheelDelta; - } else if (pskl.utils.UserAgent.isFirefox) { - delta = -40 * event.deltaY; - } - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - if(this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (this.dragHandler.isDragging()) { - this.dragHandler.stopDrag(); - } else if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) { - return this.renderer.reverseCoordinates(spriteX, spriteY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.getAvailableHeight_(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.getAvailableWidth_(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.getOffset = function () { - return this.compositeRenderer.getOffset(); - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.drawing'); - - /** - * Multiplier applied between the mouse movement and viewport movement - * @type {Number} - */ - var MULTIPLIER = 2; - - /** - * Dedicated handler to drag the drawing canvas using the mouse - * Will store the initial coordinates as well as the status of the drag - * @param {DrawingController} drawingController - */ - ns.DragHandler = function (drawingController) { - this.drawingController = drawingController; - - this.isDragging_ = false; - this.updateOrigin_(-1, -1); - }; - - /** - * Initialize a drag session. - * @param {Number} x : x coordinate of the mouse event that initiated the drag - * @param {Number} y : y coordinate of the mouse event that initiated the drag - */ - ns.DragHandler.prototype.startDrag = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - }; - - /** - * Update the drag status - * @param {Number} x : x coordinate of the mouse event that triggered the update - * @param {Number} y : y coordinate of the mouse event that triggered the update - */ - ns.DragHandler.prototype.updateDrag = function (x, y) { - var currentOffset = this.drawingController.getOffset(); - var offset = this.calculateOffset_(x, y); - if (currentOffset.y !== offset.y || currentOffset.x !== offset.x) { - this.isDragging_ = true; - this.drawingController.setOffset(offset.x, offset.y); - - // retrieve the updated coordinates after moving the sprite - // and store them as the new drag origin - var coords = this.drawingController.getSpriteCoordinates(x, y); - this.updateOrigin_(coords.x, coords.y); - } - }; - - /** - * Stop the drag session - */ - ns.DragHandler.prototype.stopDrag = function () { - this.isDragging_ = false; - this.origin = null; - }; - - /** - * Will return true if the drag handler effectively MOVED the offset - * during the current drag session - */ - ns.DragHandler.prototype.isDragging = function () { - return this.isDragging_; - }; - - ns.DragHandler.prototype.calculateOffset_ = function (x, y) { - var coords = this.drawingController.getSpriteCoordinates(x, y); - var currentOffset = this.drawingController.getOffset(); - - var offset = { - x : currentOffset.x - MULTIPLIER * (coords.x - this.origin.x), - y : currentOffset.y - MULTIPLIER * (coords.y - this.origin.y) - }; - - return offset; - }; - - ns.DragHandler.prototype.updateOrigin_ = function (x, y) { - this.origin = this.origin || {}; - this.origin.x = x; - this.origin.y = y; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.FramesListController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.FramesListController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.FramesListController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.FramesListController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.FramesListController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.FramesListController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.FramesListController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.FramesListController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.FramesListController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.FramesListController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.FramesListController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - var height = this.zoom * this.piskelController.getCurrentFrame().getHeight(); - var horizontalMargin = (Constants.PREVIEW_FILM_SIZE - height) / 2; - canvasContainer.style.marginTop = horizontalMargin + 'px'; - - var width = this.zoom * this.piskelController.getCurrentFrame().getWidth(); - var verticalMargin = (Constants.PREVIEW_FILM_SIZE - width) / 2; - canvasContainer.style.marginLeft = verticalMargin + 'px'; - canvasContainer.style.marginRight = verticalMargin + 'px'; - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.FramesListController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.FramesListController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.FramesListController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.utils.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.FramesListController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var frameSize = Math.max(frame.getHeight(), frame.getWidth()); - - return Constants.PREVIEW_FILM_SIZE/frameSize; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - this.updateButtonStatus_(); - }; - - ns.LayersListController.prototype.updateButtonStatus_ = function () { - var layers = this.piskelController.getLayers(); - var currentLayer = this.piskelController.getCurrentLayer(); - var index = this.piskelController.getCurrentLayerIndex(); - - var isLast = index === 0; - var isOnly = layers.length === 1; - var isFirst = index === layers.length - 1; - - this.toggleButtonDisabledState_('up', isFirst); - this.toggleButtonDisabledState_('down', isLast); - this.toggleButtonDisabledState_('merge', isLast); - this.toggleButtonDisabledState_('delete', isOnly); - }; - - ns.LayersListController.prototype.toggleButtonDisabledState_ = function (buttonAction, isDisabled) { - var button = document.querySelector('.layers-button[data-action="'+buttonAction+'"]'); - if (isDisabled) { - button.setAttribute('disabled', 'disabled'); - } else { - button.removeAttribute('disabled'); - } - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } - }; - - ns.LayersListController.prototype.renameCurrentLayer_ = function () { - var layer = this.piskelController.getCurrentLayer(); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.mergeDownCurrentLayer_ = function () { - var index = this.piskelController.getCurrentLayerIndex(); - this.piskelController.mergeDownLayerAt(index); - this.renderLayerList_(); - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } else if (action == 'merge') { - this.mergeDownCurrentLayer_(); - } else if (action == 'edit') { - this.renameCurrentLayer_(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - ns.PopupPreviewController = function (piskelController) { - this.piskelController = piskelController; - this.popup = null; - this.renderer = null; - this.renderFlag = false; - }; - - ns.PopupPreviewController.prototype.init = function () { - pskl.utils.Event.addEventListener(window, 'unload', this.onMainWindowUnload_, this); - }; - - ns.PopupPreviewController.prototype.isOpen = function () { - return !!this.popup; - }; - - ns.PopupPreviewController.prototype.open = function () { - if (!this.isOpen()) { - this.popup = window.open('popup-preview.html', '', 'width=320,height=320'); - } - }; - - ns.PopupPreviewController.prototype.onPopupLoaded = function () { - pskl.utils.Event.addEventListener(this.popup, 'resize', this.onWindowResize_, this); - pskl.utils.Event.addEventListener(this.popup, 'unload', this.onPopupClosed_, this); - var container = this.popup.document.querySelector('.preview-container'); - this.renderer = new pskl.rendering.frame.TiledFrameRenderer($(container)); - this.updateZoom_(); - this.renderFlag = true; - }; - - - ns.PopupPreviewController.prototype.render = function (frame) { - if (this.isOpen() && this.renderer) { - this.renderer.render(frame); - this.renderFlag = false; - } - }; - - ns.PopupPreviewController.prototype.onWindowResize_ = function (frame) { - this.updateZoom_(); - this.renderFlag = true; - }; - - ns.PopupPreviewController.prototype.updateZoom_ = function () { - var documentElement = this.popup.document.documentElement; - var wZoom = documentElement.clientWidth / this.piskelController.getWidth(); - var hZoom = documentElement.clientHeight / this.piskelController.getHeight(); - var zoom = Math.min(wZoom, hZoom); - - this.renderer.setZoom(zoom); - - var height = this.piskelController.getHeight() * zoom; - var width = this.piskelController.getWidth() * zoom; - - var container = this.popup.document.querySelector('.preview-container'); - container.style.height = height + 'px'; - container.style.width = width + 'px'; - - var horizontalMargin = (documentElement.clientHeight - height) / 2; - container.style.marginTop = horizontalMargin + 'px'; - container.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (documentElement.clientWidth - width) / 2; - container.style.marginLeft = verticalMargin + 'px'; - container.style.marginRight = verticalMargin + 'px'; - }; - - ns.PopupPreviewController.prototype.onPopupClosed_ = function () { - var popup = this.popup; - console.log(popup); - this.popup = null; - }; - - ns.PopupPreviewController.prototype.onMainWindowUnload_ = function () { - if (this.isOpen()) { - this.popup.close(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.preview'); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.PreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.renderFlag = true; - - this.fpsRangeInput = $('#preview-fps'); - this.fpsCounterDisplay = $('#display-fps'); - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - this.popupPreviewController = new ns.PopupPreviewController(piskelController); - }; - - ns.PreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this)); - document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.utils.Event.addEventListener('.open-popup-preview-button', 'click', this.onOpenPopupPreviewClick_, this); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - $.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true)); - $.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true)); - - this.popupPreviewController.init(); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - this.updateMaxFPS_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.onOpenPopupPreviewClick_ = function () { - this.popupPreviewController.open(); - }; - - ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else if (name == pskl.UserSettings.MAX_FPS) { - this.updateMaxFPS_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.PreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.PreviewController.prototype.updateMaxFPS_ = function () { - var maxFps = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.fpsRangeInput.get(0).setAttribute('max', maxFps); - this.setFPS(Math.min(this.fps, maxFps)); - }; - - ns.PreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.PreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.PreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.PreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt(this.fpsRangeInput[0].value, 10)); - - }; - - ns.PreviewController.prototype.setFPS = function (fps) { - if (typeof fps === 'number') { - this.fps = fps; - // reset - this.fpsRangeInput.get(0).value = 0; - // set proper value - this.fpsRangeInput.get(0).value = this.fps; - this.fpsRangeInput.blur(); - this.fpsCounterDisplay.html(this.fps + ' FPS'); - } - }; - - ns.PreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.PreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = this.getNextIndex_(delta); - if (this.shoudlRender_() || this.currentIndex != index) { - this.currentIndex = index; - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - this.renderFlag = false; - - this.popupPreviewController.render(frame); - } - }; - - ns.PreviewController.prototype.getNextIndex_ = function (delta) { - if (this.fps === 0) { - return this.piskelController.getCurrentFrameIndex(); - } else { - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (!this.piskelController.hasFrameAt(index)) { - this.elapsedTime = 0; - index = 0; - } - return index; - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.PreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var hZoom = PREVIEW_SIZE / frame.getHeight(), - wZoom = PREVIEW_SIZE / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.PreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.PreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + 'px'; - containerEl.style.width = width + 'px'; - - var horizontalMargin = (PREVIEW_SIZE - height) / 2; - containerEl.style.marginTop = horizontalMargin + 'px'; - containerEl.style.marginBottom = horizontalMargin + 'px'; - - var verticalMargin = (PREVIEW_SIZE - width) / 2; - containerEl.style.marginLeft = verticalMargin + 'px'; - containerEl.style.marginRight = verticalMargin + 'px'; - }; - - ns.PreviewController.prototype.setRenderFlag_ = function (bool) { - this.renderFlag = bool; - }; - - ns.PreviewController.prototype.shoudlRender_ = function () { - return this.renderFlag || this.popupPreviewController.renderFlag; - }; - - ns.PreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, previewController, drawingController, container) { - this.piskelController = piskelController; - this.previewController = previewController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - this.isVisible = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.minimapEl = document.createElement('DIV'); - this.minimapEl.className = 'minimap-crop-frame'; - this.minimapEl.style.display = 'none'; - $(this.container).append(this.minimapEl); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var verticalRatio = this.getVerticalRatio_(); - var horizontalRatio = this.getHorizontalRatio_(); - if (verticalRatio > 1 || horizontalRatio > 1) { - this.displayMinimap_(); - } else { - this.hideMinimap_(); - } - }; - - ns.MinimapController.prototype.displayMinimap_ = function () { - var minimapSize = this.getMinimapSize_(); - var previewSize = this.getPreviewSize_(); - - var containerHeight = this.container.height(); - var containerWidth = this.container.width(); - - // offset(x, y) in frame pixels - var offset = this.drawingController.getRenderer().getOffset(); - - // the preview is centered in a square container - // if the sprite is not a square, a margin is needed on the appropriate coordinate - // before adding the offset coming from the drawing area - var leftMargin = (containerWidth - Math.max(minimapSize.width, previewSize.width))/2; - var leftOffset = offset.x * this.previewController.getZoom(); - var left = leftMargin + leftOffset; - - var topMargin = (containerHeight - Math.max(minimapSize.height, previewSize.height))/2; - var topOffset = offset.y * this.previewController.getZoom(); - var top = topMargin + topOffset; - - this.minimapEl.style.display = 'block'; - this.minimapEl.style.width = Math.min(minimapSize.width, containerWidth) + 'px'; - this.minimapEl.style.height = Math.min(minimapSize.height, containerHeight) + 'px'; - this.minimapEl.style.left = Math.max(0, left) + 'px'; - this.minimapEl.style.top = Math.max(0, top) + 'px'; - - this.isVisible = true; - }; - - ns.MinimapController.prototype.getMinimapSize_ = function () { - // Calculate the ratio to translate drawing area sizes to animated preview sizes - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var animatedPreviewZoom = this.previewController.getZoom(); - var ratio = drawingAreaZoom / animatedPreviewZoom; - - var displaySize = this.drawingController.getRenderer().getDisplaySize(); - var minimapWidth = displaySize.width / ratio; - var minimapHeight = displaySize.height / ratio; - - return { - width : minimapWidth, - height: minimapHeight - }; - }; - - ns.MinimapController.prototype.getPreviewSize_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewWidth = frame.getWidth() * this.previewController.getZoom(); - var previewHeight = frame.getHeight() * this.previewController.getZoom(); - - return { - width : previewWidth, - height: previewHeight - }; - }; - - ns.MinimapController.prototype.hideMinimap_ = function () { - this.minimapEl.style.display = 'none'; - this.isVisible = false; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isVisible && this.isClicked) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.previewController.getCoordinates(x, y); - - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / this.getHorizontalRatio_(); - var height = frameHeight / this.getVerticalRatio_(); - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getVerticalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalHeight = frame.getHeight() * drawingAreaZoom; - var frameDisplayHeight = this.drawingController.getRenderer().getDisplaySize().height; - - return frameTotalHeight / frameDisplayHeight; - }; - - ns.MinimapController.prototype.getHorizontalRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var frame = this.piskelController.getCurrentFrame(); - var frameTotalWidth = frame.getWidth() * drawingAreaZoom; - var frameDisplayWidth = this.drawingController.getRenderer().getDisplaySize().width; - - return frameTotalWidth / frameDisplayWidth; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()), - toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()), - toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()), - toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()), - toDescriptor('move', 'M', new pskl.tools.drawing.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - - $.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.tools.drawing.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) { - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - return pskl.utils.Array.find(this.tools, function (tool) { - return tool.instance.toolId == toolId; - }); - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var html = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - html += this.toolIconRenderer.render(tool.instance, tool.shortcut); - } - $('#tools-container').html(html); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteService = pskl.app.paletteService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - - var createPaletteButton_ = document.querySelector('.create-palette-button'); - var editPaletteButton_ = document.querySelector('.edit-palette-button'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - editPaletteButton_.addEventListener('click', this.onEditPaletteClick_.bind(this)); - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - - pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this)); - pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this)); - - this.fillPaletteList(); - this.updateFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = this.paletteService.getPalettes(); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.colorPaletteSelect_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - - var colors = this.getSelectedPaletteColors_(); - - if (colors.length > 0) { - var html = colors.map(function (color, index) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - } else { - this.colorListContainer_.innerHTML = pskl.utils.Template.get('palettes-list-no-colors-partial'); - } - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var palette = this.getSelectedPalette_(); - if (palette) { - colors = palette.getColors(); - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.getSelectedPalette_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - return this.paletteService.getPaletteById(paletteId); - }; - - ns.PalettesListController.prototype.selectNextColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() + 1); - }; - - ns.PalettesListController.prototype.selectPreviousColor_ = function () { - this.selectColor_(this.getCurrentColorIndex_() - 1); - }; - - ns.PalettesListController.prototype.getCurrentColorIndex_ = function () { - var currentIndex = 0; - var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME); - if (selectedColor) { - currentIndex = parseInt(selectedColor.dataset.colorIndex, 10); - } - return currentIndex; - }; - - ns.PalettesListController.prototype.selectColor_ = function (index) { - var colors = this.getSelectedPaletteColors_(); - var color = colors[index]; - if (color) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } - }; - - ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.SELECTED_PALETTE) { - this.updateFromUserSettings(); - } - }; - - ns.PalettesListController.prototype.updateFromUserSettings = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - this.fillColorListContainer(); - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - this.selectPalette(paletteId); - this.colorPaletteSelect_.blur(); - }; - - ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); - }; - - ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : paletteId - }); - }; - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.updateFromUserSettings(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.ProgressBarController = function () { - this.template = pskl.utils.Template.get('progress-bar-template'); - this.progressBar = null; - this.progressBarStatus = null; - - this.showProgressTimer_ = 0; - }; - - ns.ProgressBarController.prototype.init = function () { - $.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this)); - $.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this)); - $.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this)); - }; - - ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) { - this.removeProgressBar_(); - this.showProgressTimer_ = window.setTimeout(this.onTimerExpired_.bind(this, progressInfo), 300); - }; - - ns.ProgressBarController.prototype.onTimerExpired_ = function (progressInfo) { - var progressBarHtml = pskl.utils.Template.replace(this.template, { - name : progressInfo.name, - status : 0 - }); - - var progressBarEl = pskl.utils.Template.createFromHTML(progressBarHtml); - document.body.appendChild(progressBarEl); - - this.progressBar = document.querySelector('.progress-bar'); - this.progressBarStatus = document.querySelector('.progress-bar-status'); - }; - - ns.ProgressBarController.prototype.updateProgress_ = function (event, progressInfo) { - if (this.progressBar && this.progressBarStatus) { - var progress = progressInfo.progress; - var width = this.progressBar.offsetWidth; - var progressWidth = width - ((progress * width) / 100); - this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; - this.progressBarStatus.innerHTML = progress + '%'; - } - }; - - ns.ProgressBarController.prototype.hideProgress_ = function (event, progressInfo) { - if (this.showProgressTimer_) { - window.clearTimeout(this.showProgressTimer_); - } - this.removeProgressBar_(); - }; - - ns.ProgressBarController.prototype.removeProgressBar_ = function () { - var progressBarContainer = document.querySelector('.progress-bar-container'); - if (progressBarContainer) { - progressBarContainer.parentNode.removeChild(progressBarContainer); - this.progressBar = null; - this.progressBarStatus = null; - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - - message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this)); - if (messageInfo.behavior) { - messageInfo.behavior(message); - } - - if (messageInfo.hideDelay) { - window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.TransformationsController = function () { - - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('flip', '', new pskl.tools.transform.Flip()), - toDescriptor('rotate', '', new pskl.tools.transform.Rotate()), - toDescriptor('clone', '', new pskl.tools.transform.Clone()) - ]; - - this.toolIconRenderer = new pskl.tools.IconMarkupRenderer(); - }; - - ns.TransformationsController.prototype.init = function () { - var container = document.querySelector('.transformations-container'); - this.toolsContainer = container.querySelector('.tools-wrapper'); - container.addEventListener('click', this.onTransformationClick.bind(this)); - this.createToolsDom_(); - }; - - - ns.TransformationsController.prototype.onTransformationClick = function (evt) { - var toolId = evt.target.dataset.toolId; - this.tools.forEach(function (tool) { - if (tool.instance.toolId === toolId) { - tool.instance.apply(evt); - } - }.bind(this)); - }; - - ns.TransformationsController.prototype.createToolsDom_ = function() { - var html = this.tools.reduce(function (p, tool) { - return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left'); - }.bind(this), ''); - this.toolsContainer.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - ns.AbstractSettingController = function () {}; - - ns.AbstractSettingController.prototype.addEventListener = function (el, type, callback) { - pskl.utils.Event.addEventListener(el, type, callback, this); - }; - - - ns.AbstractSettingController.prototype.destroy = function () { - pskl.utils.Event.removeAllEventListeners(this); - this.nullifyDomReferences_(); - }; - - ns.AbstractSettingController.prototype.nullifyDomReferences_ = function () { - for (var key in this) { - if (this.hasOwnProperty(key)) { - var isHTMLElement = this[key] && this[key].nodeName; - if (isHTMLElement) { - this[key] = null; - } - } - } - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - pskl.utils.inherit(ns.ApplicationSettingsController, pskl.controller.settings.AbstractSettingController); - - ns.ApplicationSettingsController.prototype.init = function() { - this.backgroundContainer = document.querySelector('.background-picker-wrapper'); - this.addEventListener(this.backgroundContainer, 'click', this.onBackgroundClick_); - - // Highlight selected background : - var background = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - var selectedBackground = this.backgroundContainer.querySelector('[data-background=' + background + ']'); - if (selectedBackground) { - selectedBackground.classList.add('selected'); - } - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - var gridSelect = document.querySelector('.grid-width-select'); - var selectedOption = gridSelect.querySelector('option[value="'+gridWidth+'"]'); - if (selectedOption) { - selectedOption.setAttribute('selected', 'selected'); - } - - this.addEventListener(gridSelect, 'change', this.onGridWidthChange_); - - // Tiled preview - var tiledPreview = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var tiledPreviewCheckbox = document.querySelector('.tiled-preview-checkbox'); - if (tiledPreview) { - tiledPreviewCheckbox.setAttribute('checked', tiledPreview); - } - this.addEventListener(tiledPreviewCheckbox, 'change', this.onTiledPreviewChange_); - - // Max FPS - var maxFpsInput = document.querySelector('.max-fps-input'); - maxFpsInput.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - this.addEventListener(maxFpsInput, 'change', this.onMaxFpsChange_); - - // Form - this.applicationSettingsForm = document.querySelector('[name="application-settings-form"]'); - this.addEventListener(this.applicationSettingsForm, 'submit', this.onFormSubmit_); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange_ = function (evt) { - var width = parseInt(evt.target.value, 10); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, width); - }; - - ns.ApplicationSettingsController.prototype.onTiledPreviewChange_ = function (evt) { - pskl.UserSettings.set(pskl.UserSettings.TILED_PREVIEW, evt.currentTarget.checked); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick_ = function (evt) { - var target = evt.target; - var background = target.dataset.background; - if (background) { - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, background); - var selected = this.backgroundContainer.querySelector('.selected'); - if (selected) { - selected.classList.remove('selected'); - } - target.classList.add('selected'); - } - }; - - ns.ApplicationSettingsController.prototype.onMaxFpsChange_ = function (evt) { - var target = evt.target; - var fps = parseInt(target.value, 10); - if (fps && !isNaN(fps)) { - pskl.UserSettings.set(pskl.UserSettings.MAX_FPS, fps); - } else { - target.value = pskl.UserSettings.get(pskl.UserSettings.MAX_FPS); - } - }; - - ns.ApplicationSettingsController.prototype.onFormSubmit_ = function (evt) { - evt.preventDefault(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController); - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = document.querySelector(".gif-upload-button"); - this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_); - - this.downloadButton = document.querySelector(".gif-download-button"); - this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.uploadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.downloadImageData_.bind(this)); - }; - - ns.GifExportController.prototype.downloadImageData_ = function (imageData) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.GifExportController.prototype.uploadImageData_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this), this.onImageUploadFailed_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.onImageUploadFailed_ = function (event, xhr) { - if (xhr.status === 500) { - $.publish(Events.SHOW_NOTIFICATION, [{ - "content": "Upload failed : " + xhr.responseText, - "hideDelay" : 5000 - }]); - } - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 5, - quality: 1, - width: this.piskelController.getWidth() * zoom, - height: this.piskelController.getHeight() * zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Building animated GIF ...'}]); - gif.on('progress', function(percentage) { - $.publish(Events.UPDATE_PROGRESS, [{"progress": (percentage*100).toFixed(1)}]); - }.bind(this)); - - gif.on('finished', function(blob) { - $.publish(Events.HIDE_PROGRESS); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings.exportimage"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController); - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelector('.png-export-preview'); - this.pngFilePrefixInput = document.getElementById('zip-prefix-name'); - this.pngFilePrefixInput.value = 'sprite_'; - - var downloadButton = document.querySelector(".png-download-button"); - this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_); - - var zipButton = document.querySelector(".zip-generate-button"); - this.addEventListener(zipButton, 'click', this.onZipButtonClick_); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var basename = this.pngFilePrefixInput.value; - var filename = basename + (i+1) + ".png"; - zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - var OPTION_CLASSNAME = 'resize-origin-option'; - - ns.AnchorWidget = function (container) { - this.container = container; - this.disabled = false; - pskl.utils.Event.addEventListener(this.container, 'click', this.onResizeOriginClick_, this); - }; - - ns.AnchorWidget.ORIGIN = { - TOPLEFT : 'TOPLEFT', - TOP : 'TOP', - TOPRIGHT : 'TOPRIGHT', - MIDDLELEFT : 'MIDDLELEFT', - MIDDLE : 'MIDDLE', - MIDDLERIGHT : 'MIDDLERIGHT', - BOTTOMLEFT : 'BOTTOMLEFT', - BOTTOM : 'BOTTOM', - BOTTOMRIGHT : 'BOTTOMRIGHT' - }; - - ns.AnchorWidget.prototype.destroy = function (evt) { - pskl.utils.Event.removeAllEventListeners(this); - this.container = null; - }; - - ns.AnchorWidget.prototype.onResizeOriginClick_ = function (evt) { - var origin = evt.target.dataset.origin; - if (origin && ns.AnchorWidget.ORIGIN[origin] && !this.disabled) { - this.setOrigin(origin); - } - }; - - ns.AnchorWidget.prototype.setOrigin = function (origin) { - this.origin = origin; - var previous = document.querySelector('.'+OPTION_CLASSNAME+'.selected'); - if (previous) { - previous.classList.remove('selected'); - } - - var selected = document.querySelector('.'+OPTION_CLASSNAME+'[data-origin="' + origin + '"]'); - if (selected) { - selected.classList.add('selected'); - this.refreshNeighbors_(selected); - } - }; - - ns.AnchorWidget.prototype.getOrigin = function () { - return this.origin; - }; - - ns.AnchorWidget.prototype.disable = function () { - this.disabled = true; - this.container.classList.add('transition'); - this.container.classList.add('disabled'); - }; - - ns.AnchorWidget.prototype.enable = function () { - this.disabled = false; - this.container.classList.remove('disabled'); - window.setTimeout(this.container.classList.remove.bind(this.container.classList, 'transition'), 250); - }; - - ns.AnchorWidget.prototype.refreshNeighbors_ = function (selected) { - var options = document.querySelectorAll('.'+OPTION_CLASSNAME); - for (var i = 0 ; i < options.length ; i++) { - options[i].removeAttribute('data-neighbor'); - } - - var selectedIndex = Array.prototype.indexOf.call(options, selected); - - this.setNeighborhood_(options[selectedIndex - 1], 'left'); - this.setNeighborhood_(options[selectedIndex + 1], 'right'); - this.setNeighborhood_(options[selectedIndex - 3], 'top'); - this.setNeighborhood_(options[selectedIndex + 3], 'bottom'); - }; - - ns.AnchorWidget.prototype.setNeighborhood_ = function (el, neighborhood) { - var origin = this.origin.toLowerCase(); - var isNeighborhoodValid = origin.indexOf(neighborhood) === -1; - if (isNeighborhoodValid) { - el.setAttribute('data-neighbor', neighborhood); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings.resize'); - - ns.ResizeController = function (piskelController) { - this.piskelController = piskelController; - - this.container = document.querySelector('.resize-canvas'); - - var anchorWidgetContainer = this.container.querySelector('.resize-origin-container'); - this.anchorWidget = new ns.AnchorWidget(anchorWidgetContainer); - }; - - pskl.utils.inherit(ns.ResizeController, pskl.controller.settings.AbstractSettingController); - - ns.ResizeController.prototype.init = function () { - this.widthInput = this.container.querySelector('[name="resize-width"]'); - this.heightInput = this.container.querySelector('[name="resize-height"]'); - - this.widthInput.value = this.piskelController.getWidth(); - this.heightInput.value = this.piskelController.getHeight(); - - this.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_); - this.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_); - - this.resizeForm = this.container.querySelector('form'); - this.addEventListener(this.resizeForm, 'submit', this.onResizeFormSubmit_); - - this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox'); - this.addEventListener(this.resizeContentCheckbox, 'change', this.onResizeContentChange_); - - this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox'); - this.addEventListener(this.maintainRatioCheckbox, 'change', this.onMaintainRatioChange_); - - this.anchorWidget.setOrigin(ns.AnchorWidget.ORIGIN.TOPLEFT); - this.lastInput = this.widthInput; - }; - - ns.ResizeController.prototype.destroy = function () { - this.anchorWidget.destroy(); - this.superclass.destroy.call(this); - }; - - ns.ResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.preventDefault(); - - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - - ns.ResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.ResizeController.prototype.onResizeContentChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.anchorWidget.disable(); - } else { - this.anchorWidget.enable(); - } - }; - - ns.ResizeController.prototype.onMaintainRatioChange_ = function (evt) { - var target = evt.target; - if (target.checked) { - this.synchronizeSizeInputs_(this.lastInput); - } - }; - - ns.ResizeController.prototype.onSizeInputKeyUp_ = function (evt) { - var target = evt.target; - if (this.maintainRatioCheckbox.checked) { - this.synchronizeSizeInputs_(target); - } - this.lastInput = target; - }; - - /** - * Based on the value of the provided sizeInput (considered as emitter) - * update the value of the other sizeInput to match the current width/height ratio - * @param {HTMLElement} origin either widthInput or heightInput - */ - ns.ResizeController.prototype.synchronizeSizeInputs_ = function (sizeInput) { - var value = parseInt(sizeInput.value, 10); - if (isNaN(value)) { - value = 0; - } - - var height = this.piskelController.getHeight(), - width = this.piskelController.getWidth(); - - if (sizeInput === this.widthInput) { - this.heightInput.value = Math.round(value * height/width); - } else if (sizeInput === this.heightInput) { - this.widthInput.value = Math.round(value * width/height); - } - }; - - /***********************/ - /* RESIZE LOGIC */ - /***********************/ - - ns.ResizeController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.widthInput.value, 10); - var height = parseInt(this.heightInput.value, 10); - if (this.resizeContentCheckbox.checked) { - return pskl.utils.FrameUtils.resize(frame, width, height, false); - } else { - var resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - var translated = this.translateCoordinates_(x, y, frame, resizedFrame); - if (resizedFrame.containsPixel(translated.x, translated.y)) { - resizedFrame.setPixel(translated.x, translated.y, color); - } - }.bind(this)); - - return resizedFrame; - } - }; - - ns.ResizeController.prototype.translateCoordinates_ = function (x, y, frame, resizedFrame) { - return { - x : this.translateX_(x, frame.width, resizedFrame.width), - y : this.translateY_(y, frame.height, resizedFrame.height) - }; - }; - - ns.ResizeController.prototype.translateX_ = function (x, width, resizedWidth) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('LEFT') != -1) { - return x; - } else if (origin.indexOf('RIGHT') != -1) { - return x - (width - resizedWidth); - } else { - return x - Math.round((width - resizedWidth)/2); - } - }; - - ns.ResizeController.prototype.translateY_ = function (y, height, resizedHeight) { - var origin = this.anchorWidget.getOrigin(); - if (origin.indexOf('TOP') != -1) { - return y; - } else if (origin.indexOf('BOTTOM') != -1) { - return y - (height - resizedHeight); - } else { - return y - Math.round((height - resizedHeight)/2); - } - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.SaveController, pskl.controller.settings.AbstractSettingController); - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - // timestamp used to generate unique name when saving as .piskel - this.timestamp = new Date(); - - // Only available in app-engine mode - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = document.querySelector('#save-online-status'); - this.saveFileStatus = document.querySelector('#save-file-status'); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = document.querySelector('#save-description'); - this.descriptionInput.value = descriptor.description; - - this.isPublicCheckbox = document.querySelector('input[name=save-public-checkbox]'); - if (descriptor.isPublic) { - this.isPublicCheckbox.setAttribute('checked', true); - } - - this.addEventListener('#save-file-button', 'click', this.saveFile_); - this.addEventListener('#save-browser-button', 'click', this.saveLocal_); - - this.saveOnlineButton = document.querySelector('#save-online-button'); - this.addEventListener(this.saveOnlineButton, 'click', this.saveOnline_); - - this.addEventListener('form[name=save-form]', 'submit', this.onSaveFormSubmit_); - - this.nameInput = document.querySelector('#save-name'); - this.nameInput.value = descriptor.name; - this.addEventListener(this.nameInput, 'keyup', this.updateLocalStatusFilename_); - - if (pskl.app.isLoggedIn()) { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-online-status-partial'); - } else { - this.saveOnlineStatus.innerHTML = pskl.utils.Template.get('save-please-login-partial'); - var container = document.querySelector('.setting-save-section'); - container.classList.add('anonymous'); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.innerHTML = pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - }); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.innerHTML = 'Saving ...'; - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.value; - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.value; - }; - - ns.SaveController.prototype.isPublic_ = function () { - return !!this.isPublicCheckbox.checked; - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = this.isPublic_(); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.innerHTML = ''; - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - }; - - pskl.utils.inherit(ns.ImportController, pskl.controller.settings.AbstractSettingController); - - ns.ImportController.prototype.init = function () { - this.hiddenFileInput = document.querySelector('[name="file-upload-input"]'); - this.addEventListener(this.hiddenFileInput, 'change', this.onFileUploadChange_); - - this.hiddenOpenPiskelInput = document.querySelector('[name="open-piskel-input"]'); - this.addEventListener(this.hiddenOpenPiskelInput, 'change', this.onOpenPiskelChange_); - - this.addEventListener('.browse-local-button', 'click', this.onBrowseLocalClick_); - this.addEventListener('.file-input-button', 'click', this.onFileInputClick_); - this.addEventListener('.open-piskel-button', 'click', this.onOpenPiskelClick_); - - this.initRestoreSession_(); - }; - - ns.ImportController.prototype.initRestoreSession_ = function () { - var previousSessionContainer = document.querySelector('.previous-session'); - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var previousSessionTemplate_ = pskl.utils.Template.get('previous-session-info-template'); - var date = pskl.utils.DateUtils.format(previousInfo.date, '{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}'); - previousSessionContainer.innerHTML = pskl.utils.Template.replace(previousSessionTemplate_, { - name : previousInfo.name, - date : date - }); - this.addEventListener('.restore-session-button', 'click', this.onRestorePreviousSessionClick_); - } else { - previousSessionContainer.innerHTML = 'No piskel backup was found on this browser.'; - } - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - var files = this.hiddenOpenPiskelInput.files; - if (files.length == 1) { - this.openPiskelFile_(files[0]); - } - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function (file) { - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - this.closeDrawer_(); - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.resize.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.exportimage.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - if (this.currentController && this.currentController.destroy) { - this.currentController.destroy(); - } - - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - - this.currentSetting = setting; - this.currentController = new settings[setting].controller(this.piskelController); - this.currentController.init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - this.destroy(); - $.publish(Events.DIALOG_HIDE); - }; - - ns.AbstractDialogController.prototype.setTitle = function (title) { - var dialogTitle = document.querySelector('.dialog-title'); - if (dialogTitle) { - dialogTitle.innerText = title; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteController = function (piskelController) { - this.paletteService = pskl.app.paletteService; - this.paletteImportService = pskl.app.paletteImportService; - }; - - pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - - ns.CreatePaletteController.prototype.init = function (paletteId) { - this.superclass.init.call(this); - - this.hiddenFileInput = document.querySelector('.create-palette-import-input'); - this.nameInput = document.querySelector('input[name="palette-name"]'); - - var buttonsContainer = document.querySelector('.create-palette-actions'); - var deleteButton = document.querySelector('.create-palette-delete'); - var downloadButton = document.querySelector('.create-palette-download-button'); - var importFileButton = document.querySelector('.create-palette-import-button'); - - this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); - this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - - buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this)); - downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this)); - importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); - - var colorsListContainer = document.querySelector('.colors-container'); - this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer); - - var palette; - var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID; - if (paletteId && !isCurrentColorsPalette) { - importFileButton.style.display = 'none'; - this.setTitle('Edit Palette'); - - var paletteObject = this.paletteService.getPaletteById(paletteId); - palette = pskl.model.Palette.fromObject(paletteObject); - } else { - downloadButton.style.display = 'none'; - deleteButton.style.display = 'none'; - this.setTitle('Create Palette'); - - var uuid = pskl.utils.Uuid.generate(); - if (isCurrentColorsPalette) { - palette = new pskl.model.Palette(uuid, 'Current colors clone', this.getCurrentColors_()); - } else { - palette = new pskl.model.Palette(uuid, 'New palette', []); - } - } - - this.setPalette_(palette); - }; - - ns.CreatePaletteController.prototype.getCurrentColors_ = function () { - var palette = this.paletteService.getPaletteById(Constants.CURRENT_COLORS_PALETTE_ID); - return palette.getColors(); - }; - - ns.CreatePaletteController.prototype.setPalette_ = function (palette) { - this.palette = palette; - this.nameInput.value = pskl.utils.unescapeHtml(palette.name); - this.colorsListWidget.setColors(palette.getColors()); - }; - - ns.CreatePaletteController.prototype.destroy = function () { - this.colorsListWidget.destroy(); - this.nameInput = null; - }; - - ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) { - var target = evt.target; - if (target.dataset.action === 'submit') { - this.saveAndSelectPalette_(); - } else if (target.dataset.action === 'cancel') { - this.closeDialog(); - } else if (target.dataset.action === 'delete') { - this.deletePalette_(); - } - }; - - ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function () { - this.palette.setColors(this.colorsListWidget.getColors()); - this.paletteService.savePalette(this.palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, this.palette.id); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.deletePalette_ = function () { - if (window.confirm('Are you sure you want to delete palette ' + this.palette.name)) { - this.paletteService.deletePaletteById(this.palette.id); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, Constants.CURRENT_COLORS_PALETTE_ID); - this.closeDialog(); - } - }; - - ns.CreatePaletteController.prototype.onDownloadButtonClick_ = function () { - var paletteWriter = new pskl.service.palette.PaletteGplWriter(this.palette); - var paletteAsString = paletteWriter.write(); - - pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.palette.name + '.gpl'); - }.bind(this), "application/json"); - }; - - ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { - this.hiddenFileInput.click(); - }; - - ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - this.paletteImportService.read(files[0], this.setPalette_.bind(this), this.displayErrorMessage_.bind(this)); - } - }; - - ns.CreatePaletteController.prototype.displayErrorMessage_ = function (message) { - message = "Could not import palette : " + message; - $.publish(Events.SHOW_NOTIFICATION, [{"content": message}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { - this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (image) { - this.importedImage_ = image; - - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.utils.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'create-palette' : { - template : 'templates/dialogs/create-palette.html', - controller : ns.CreatePaletteController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette')); - - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.classList.add(dialogId); - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - var DEFAULT_COLOR = '#000000'; - - ns.ColorsList = function (container) { - this.selectedIndex = -1; - this.palette = new pskl.model.Palette('tmp', 'tmp', []); - this.container = container; - - this.colorsList = this.container.querySelector('.colors-list'); - this.colorPreviewEl = this.container.querySelector('.color-preview'); - - $(container).sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onColorDrop_.bind(this), - items: '.create-palette-color' - }); - - this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - - var colorPickerContainer = container.querySelector('.color-picker-container'); - this.hslRgbColorPicker = new pskl.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); - this.hslRgbColorPicker.init(); - }; - - ns.ColorsList.prototype.setColors = function (colors) { - if (colors.length === 0) { - colors.push(DEFAULT_COLOR); - } - - this.palette.setColors(colors); - - this.selectColor_(0); - this.refresh_(); - }; - - ns.ColorsList.prototype.getColors = function () { - return this.palette.getColors(); - }; - - ns.ColorsList.prototype.destroy = function () { - this.hslRgbColorPicker.destroy(); - this.container = null; - this.colorsList = null; - this.colorPreviewEl = null; - }; - - /** - * Lightweight refresh only changing the color of one element of the palette color list - */ - ns.ColorsList.prototype.refreshColorElement_ = function (index) { - var color = this.palette.get(this.selectedIndex); - var element = document.querySelector('[data-palette-index="'+index+'"]'); - if (element) { - element.style.background = color; - element.classList.toggle('light-color', this.isLight_(color)); - } - }; - - ns.ColorsList.prototype.onColorContainerClick_ = function (evt) { - var target = evt.target; - if (target.classList.contains('create-palette-color')) { - this.onPaletteColorClick_(evt, target); - } else if (target.classList.contains('create-palette-new-color')) { - this.onNewColorClick_(evt, target); - } else if (target.classList.contains('create-palette-remove-color')) { - this.onRemoveColorClick_(evt, target); - } - this.refresh_(); - }; - - ns.ColorsList.prototype.onColorUpdated_ = function (color) { - var rgbColor = color.toRgbString(); - this.colorPreviewEl.style.background = rgbColor; - if (this.palette) { - this.palette.set(this.selectedIndex, rgbColor); - this.refreshColorElement_(this.selectedIndex); - } - }; - - ns.ColorsList.prototype.onPaletteColorClick_ = function (evt, target) { - var index = parseInt(target.dataset.paletteIndex,10); - this.selectColor_(index); - }; - - ns.ColorsList.prototype.onRemoveColorClick_ = function (evt, target) { - var colorElement = target.parentNode; - var index = parseInt(colorElement.dataset.paletteIndex,10); - this.removeColor_(index); - }; - - ns.ColorsList.prototype.onNewColorClick_ = function (evt, target) { - var newColor = this.palette.get(this.selectedIndex) || '#000000'; - this.palette.add(newColor); - this.selectColor_(this.palette.size()-1); - }; - - ns.ColorsList.prototype.refresh_ = function () { - var html = ""; - var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.getColors(); - - colors.forEach(function (color, index) { - var isSelected = (index === this.selectedIndex); - - html += pskl.utils.Template.replace(tpl, { - 'color':color, index:index, - ':selected':isSelected, - ':light-color':this.isLight_(color) - }); - }.bind(this)); - - html += '
      • +
      • '; - - this.colorsList.innerHTML = html; - }; - - ns.ColorsList.prototype.selectColor_ = function (index) { - this.selectedIndex = index; - this.hslRgbColorPicker.setColor(this.palette.get(index)); - }; - - ns.ColorsList.prototype.removeColor_ = function (index) { - this.palette.removeAt(index); - this.refresh_(); - }; - - ns.ColorsList.prototype.isLight_ = function (color) { - var rgb = window.tinycolor(color).toRgb(); - return rgb.r+rgb.b+rgb.g > 128*3; - }; - - ns.ColorsList.prototype.onColorDrop_ = function (evt, drop) { - var colorElement = drop.item.get(0); - - var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); - var newIndex = $('.create-palette-color').index(drop.item); - this.palette.move(oldIndex, newIndex); - - this.selectedIndex = newIndex; - - this.refresh_(); - }; -})();;(function () { - var ns = $.namespace('pskl.widgets'); - - ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { - this.container = container; - this.colorUpdatedCallback = colorUpdatedCallback; - - this.tinyColor = null; - this.hsvColor = null; - this.rgbColor = null; - - this.lastInputTimestamp_ = 0; - }; - - ns.HslRgbColorPicker.prototype.init = function () { - var isChromeOrFirefox = pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isFirefox; - var changeEvent = isChromeOrFirefox ? 'input' : 'change'; - this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this)); - this.container.addEventListener('keydown', this.onKeydown_.bind(this)); - this.container.addEventListener('focusout', this.onBlur_.bind(this)); - - this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); - - $(this.spectrumEl).spectrum({ - flat: true, - showButtons: false, - move : this.setColor.bind(this), - change : this.setColor.bind(this) - }); - - this.setColor("#000000"); - }; - - ns.HslRgbColorPicker.prototype.destroy = function () { - this.container = null; - this.spectrumEl = null; - }; - - ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) { - var target = evt.target; - if (target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = target.value; - - this.updateColor_(value, model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.onKeydown_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - - if (model === 'rgb' || model === 'hsv') { - var increment = this.getIncrement_(evt); - if (increment) { - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - this.updateColor_(value + increment, model, dimension); - } - } - } - }; - - ns.HslRgbColorPicker.prototype.getIncrement_ = function (evt) { - var increment = 0; - var key = pskl.service.keyboard.KeycodeTranslator.toChar(evt.keyCode); - if (key === 'up') { - increment = 1; - } else if (key === 'down') { - increment = -1; - } - - if (evt.shiftKey) { - increment = increment * 5; - } - - return increment; - }; - - ns.HslRgbColorPicker.prototype.updateColor_ = function (inputValue, model, dimension) { - var value = this.toModelValue_(inputValue, model, dimension); - if (model === 'hsv' || model === 'rgb') { - if (!isNaN(value)) { - var color = this.getColor_(model); - color[dimension] = this.normalizeDimension_(value, dimension); - this.setColor(color); - } - } else if (model === 'hex') { - if (/^#([a-f0-9]{3}){1,2}$/i.test(value)) { - this.setColor(value); - } - } - }; - - ns.HslRgbColorPicker.prototype.onBlur_ = function (evt) { - var target = evt.target; - - var isInputText = target.getAttribute('type').toLowerCase() === 'text'; - if (isInputText && target.dataset.dimension) { - var model = target.dataset.model; - var dimension = target.dataset.dimension; - target.value = this.toInputValue_(model, dimension); - } - }; - - ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - this.rgbColor = this.tinyColor.toRgb(); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.colorUpdatedCallback(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.HslRgbColorPicker.prototype.updateInputs = function () { - var inputs = this.container.querySelectorAll('input'); - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - var value = this.toInputValue_(model, dimension); - if (input.value != value) { - input.value = value; - } - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.HslRgbColorPicker.prototype.toInputValue_ = function (model, dimension) { - var value; - - if (model === 'rgb' || model === 'hsv') { - var color = this.getColor_(model); - value = color[dimension]; - - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - value = Math.round(value); - } else if (model === 'hex') { - value = this.tinyColor.toHexString(true); - } - - return value; - }; - - ns.HslRgbColorPicker.prototype.toModelValue_ = function (value, model, dimension) { - var modelValue; - - if (model === 'rgb' || model === 'hsv') { - modelValue = parseInt(value, 10); - if (dimension === 'v' || dimension === 's') { - modelValue = modelValue/100; - } - } else if (model === 'hex') { - modelValue = value; - } - - return modelValue; - }; - - ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { - var isTinyColor = typeof color == 'object' && color.hasOwnProperty('_tc_id'); - if (isTinyColor) { - return color; - } else { - return window.tinycolor(pskl.utils.copy(color)); - } - }; - - ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : this.normalizeDimension_(color.h, 'h'), - s : this.normalizeDimension_(color.s, 's'), - v : this.normalizeDimension_(color.v, 'v') - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.HslRgbColorPicker.prototype.normalizeDimension_ = function (value, dimension) { - var range = this.getDimensionRange_(dimension); - return Math.max(range[0], Math.min(range[1], value)); - }; - - /** - * Update background colors for range inputs - */ - ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - var colors = this.getSliderBackgroundColors_(model, dimension); - slider.style.backgroundImage = "linear-gradient(to right, " + colors.start + " 0, " + colors.end + " 100%)"; - } - }; - - ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) { - var color = this.getColor_(model); - var start = pskl.utils.copy(color); - var end = pskl.utils.copy(color); - - var range = this.getDimensionRange_(dimension); - start[dimension] = range[0]; - end[dimension] = range[1]; - - return { - start : window.tinycolor(start).toRgbString(), - end : window.tinycolor(end).toRgbString() - }; - }; - - ns.HslRgbColorPicker.prototype.getDimensionRange_ = function (d) { - if (d === 'h') { - return [0, 359]; - } else if (d === 's' || d === 'v') { - return [0, 1]; - } else if (d === 'r' || d === 'g' || d === 'b') { - return [0, 255]; - } - }; - - ns.HslRgbColorPicker.prototype.getColor_ = function (model) { - var color; - if (model === 'hsv') { - color = this.hsvColor; - } else if (model === 'rgb'){ - color = this.rgbColor; - } - return color; - }; - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var data = { - framesheet : this.piskelController.serialize(), - fps : this.piskelController.getFPS(), - name : descriptor.name, - description : descriptor.description, - frames : this.piskelController.getFrameCount(), - first_frame_as_png : pskl.app.getFirstFrameAsPng(), - framesheet_as_png : pskl.app.getFramesheetAsPng() - }; - - if (descriptor.isPublic) { - data['public'] = true; - } - - var success = function () { - callbacks.success(); - callbacks.after(); - }; - - var error = function (response) { - callbacks.error(response.status); - callbacks.after(); - }; - - pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - // 1 minute = 1000 * 60 - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - this.savePiskel_('prev', previousPiskel, previousInfo); - } - - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - this.savePiskel_('next', this.piskelController.serialize(), JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(previousInfo.fps); - }); - }; - - ns.BackupService.prototype.savePiskel_ = function (type, piskel, info) { - try { - window.localStorage.setItem('bkp.' + type +'.piskel', piskel); - window.localStorage.setItem('bkp.' + type +'.info', info); - } catch (e) { - console.error('Could not save piskel backup in localStorage.', e); - } - }; -})(); - - - - -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.HistoryService = function (piskelController, shortcutService, deserializer) { - this.piskelController = piskelController || pskl.app.piskelController; - this.shortcutService = shortcutService || pskl.app.shortcutService; - this.deserializer = deserializer || pskl.utils.serialization.Deserializer; - - this.stateQueue = []; - this.currentIndex = -1; - - this.lastLoadState = -1; - }; - - // Force to save a state as a SNAPSHOT - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - - // Default save state - ns.HistoryService.REPLAY = 'REPLAY'; - - // Period (in number of state saved) between two snapshots - ns.HistoryService.SNAPSHOT_PERIOD = 50; - - // Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming) - ns.HistoryService.LOAD_STATE_INTERVAL = 50; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); - - this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, action) { - this.saveState(action); - }; - - ns.HistoryService.prototype.saveState = function (action) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : action, - frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex, - layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = action.type === ns.HistoryService.SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0; - if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - } - - this.stateQueue.push(state); - $.publish(Events.HISTORY_STATE_SAVED); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - // Should only do this when going backwards - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - $.publish(Events.HISTORY_STATE_LOADED); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service.color'); - - var LOW_SAT = 0.1; - var LOW_LUM = 0.1; - var HI_LUM = 0.9; - - - var HUE_STEP = 36; - var HUE_BAGS = 10; - var HUE_BOUNDS = []; - for (var i = 0 ; i < HUE_BAGS ; i++) { - HUE_BOUNDS.push(i * HUE_STEP); - } - - ns.ColorSorter = function () { - this.colorsHslMap_ = {}; - }; - - ns.ColorSorter.prototype.sort = function (colors) { - this.colorsHslMap_ = {}; - - colors.forEach(function (color) { - this.colorsHslMap_[color] = window.tinycolor(color).toHsl(); - }.bind(this)); - - // sort by most frequent color - var darkColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l <= LOW_LUM; - }.bind(this)); - - var brightColors = colors.filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.l >= HI_LUM; - }.bind(this)); - - var desaturatedColors = colors.filter(function (c) { - return brightColors.indexOf(c) === -1 && darkColors.indexOf(c) === -1; - }).filter(function (c) { - var hsl = this.colorsHslMap_[c]; - return hsl.s <= LOW_SAT; - }.bind(this)); - - darkColors = this.sortOnHslProperty_(darkColors, 'l'); - brightColors = this.sortOnHslProperty_(brightColors, 'l'); - desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); - - var sortedColors = darkColors.concat(brightColors, desaturatedColors); - - var regularColors = colors.filter(function (c) { - return sortedColors.indexOf(c) === -1; - }); - - var regularColorsBags = HUE_BOUNDS.map(function (hue) { - var bagColors = regularColors.filter(function (color) { - var hsl = this.colorsHslMap_[color]; - return (hsl.h >= hue && hsl.h < hue + HUE_STEP); - }.bind(this)); - - return this.sortRegularColors_(bagColors); - }.bind(this)); - - return Array.prototype.concat.apply(sortedColors, regularColorsBags); - }; - - ns.ColorSorter.prototype.sortRegularColors_ = function (colors) { - var sortedColors = colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - var hDiff = Math.abs(hsl1.h - hsl2.h); - var sDiff = Math.abs(hsl1.s - hsl2.s); - var lDiff = Math.abs(hsl1.l - hsl2.l); - if (hDiff < 10) { - if (sDiff > lDiff) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - return this.compareValues_(hsl1.l, hsl2.l); - } - } else { - return this.compareValues_(hsl1.h, hsl2.h); - } - }.bind(this)); - - return sortedColors; - }; - - ns.ColorSorter.prototype.sortOnHslProperty_ = function (colors, property) { - return colors.sort(function (c1, c2) { - var hsl1 = this.colorsHslMap_[c1]; - var hsl2 = this.colorsHslMap_[c2]; - return this.compareValues_(hsl1[property], hsl2[property]); - }.bind(this)); - }; - - ns.ColorSorter.prototype.compareValues_ = function (v1, v2) { - if (v1 > v2) { - return 1; - } else if (v1 < v2) { - return -1; - } - return 0; - }; - -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.CurrentColorsPalette = function () { - this.name = 'Current colors'; - this.id = Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsPalette.prototype.getColors = function () { - return pskl.app.currentColorsService.getCurrentColors(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteService = function () { - this.dynamicPalettes = []; - this.localStorageService = window.localStorage; - }; - - ns.PaletteService.prototype.getPalettes = function () { - var palettesString = this.localStorageService.getItem('piskel.palettes'); - var palettes = JSON.parse(palettesString) || []; - palettes = palettes.map(function (palette) { - return pskl.model.Palette.fromObject(palette); - }); - - return this.dynamicPalettes.concat(palettes); - }; - - ns.PaletteService.prototype.getPaletteById = function (paletteId) { - var palettes = this.getPalettes(); - return this.findPaletteInArray_(paletteId, palettes); - }; - - ns.PaletteService.prototype.savePalette = function (palette) { - var palettes = this.getPalettes(); - var existingPalette = this.findPaletteInArray_(palette.id, palettes); - if (existingPalette) { - var currentIndex = palettes.indexOf(existingPalette); - palettes.splice(currentIndex, 1, palette); - } else { - palettes.push(palette); - } - - this.savePalettes_(palettes); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteService.prototype.addDynamicPalette = function (palette) { - this.dynamicPalettes.push(palette); - }; - - ns.PaletteService.prototype.deletePaletteById = function (id) { - var palettes = this.getPalettes(); - var filteredPalettes = palettes.filter(function (palette) { - return palette.id !== id; - }); - - this.savePalettes_(filteredPalettes); - }; - - ns.PaletteService.prototype.savePalettes_ = function (palettes) { - palettes = palettes.filter(function (palette) { - return this.dynamicPalettes.indexOf(palette) === -1; - }.bind(this)); - this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteGplWriter = function (palette) { - this.palette = palette; - }; - - ns.PaletteGplWriter.prototype.write = function () { - var lines = []; - lines.push('GIMP Palette'); - lines.push('Name: ' + this.palette.name); - lines.push('Columns: 0'); - lines.push('#'); - this.palette.getColors().forEach(function (color) { - lines.push(this.writeColorLine(color)); - }.bind(this)); - lines.push('\r\n'); - - return lines.join('\r\n'); - }; - - ns.PaletteGplWriter.prototype.writeColorLine = function (color) { - var tinycolor = window.tinycolor(color); - var rgb = tinycolor.toRgb(); - var strBuffer = []; - strBuffer.push(this.padString(rgb.r, 3)); - strBuffer.push(this.padString(rgb.g, 3)); - strBuffer.push(this.padString(rgb.b, 3)); - strBuffer.push('Untitled'); - - return strBuffer.join(' '); - }; - - ns.PaletteGplWriter.prototype.padString = function (str, size) { - str = str.toString(); - var pad = (new Array(1+size-str.length)).join(' '); - return pad + str; - }; - -})(); -;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.AbstractPaletteFileReader = function (file, onSuccess, onError, colorLineRegexp) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - this.colorLineRegexp = colorLineRegexp; - }; - - ns.AbstractPaletteFileReader.prototype.extractColorFromLine = Constants.ABSTRACT_FUNCTION; - - ns.AbstractPaletteFileReader.prototype.read = function () { - pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this)); - }; - - ns.AbstractPaletteFileReader.prototype.onFileLoaded_ = function (content) { - var text = pskl.utils.Base64.toText(content); - var lines = text.match(/[^\r\n]+/g); - - var colorLines = lines.filter(function (l) { - return this.colorLineRegexp.test(l); - }.bind(this)); - - var colors = colorLines.map(this.extractColorFromLine.bind(this)); - - if (colors.length) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name, colors); - this.onSuccess(palette); - } else { - this.onError(); - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/; - var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; - - ns.PaletteGplReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteGplReader, ns.AbstractPaletteFileReader); - - ns.PaletteGplReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = window.tinycolor({ - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10) - }); - - return color.toRgbString(); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - ns.PaletteImageReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - - this.colorSorter_ = new pskl.service.color.ColorSorter(); - }; - - ns.PaletteImageReader.prototype.read = function () { - pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this)); - }; - - ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) { - var imageProcessor = new pskl.worker.ImageProcessor(image, - this.onWorkerSuccess_.bind(this), - this.onWorkerStep_.bind(this), - this.onWorkerError_.bind(this)); - - $.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]); - - imageProcessor.process(); - }; - - ns.PaletteImageReader.prototype.onWorkerSuccess_ = function (event) { - var data = event.data; - var colorsMap = data.colorsMap; - - var colors = Object.keys(colorsMap); - - if (colors.length > 200) { - this.onError('Too many colors : ' + colors.length); - } else { - var uuid = pskl.utils.Uuid.generate(); - var sortedColors = this.colorSorter_.sort(colors); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', sortedColors); - - this.onSuccess(palette); - } - $.publish(Events.HIDE_PROGRESS); - }; - - ns.PaletteImageReader.prototype.onWorkerStep_ = function (event) { - var progress = event.data.progress; - $.publish(Events.UPDATE_PROGRESS, [{"progress": progress}]); - }; - - ns.PaletteImageReader.prototype.onWorkerError_ = function (event) { - $.publish(Events.HIDE_PROGRESS); - this.onError('Unable to process the image : ' + event.data.message); - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})/; - - ns.PalettePalReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PalettePalReader, ns.AbstractPaletteFileReader); - - ns.PalettePalReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = 'rgb(' + matches[1] + ',' + matches[2] + ',' + matches[3] + ')'; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette.reader'); - - var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/; - - ns.PaletteTxtReader = function (file, onSuccess, onError) { - this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE); - }; - - pskl.utils.inherit(ns.PaletteTxtReader, ns.AbstractPaletteFileReader); - - ns.PaletteTxtReader.prototype.extractColorFromLine = function (line) { - var matches = line.match(RE_COLOR_LINE); - var color = "#" + matches[1] + matches[2] + matches[3]; - return color; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var fileReaders = { - 'gpl' : ns.reader.PaletteGplReader, - 'pal' : ns.reader.PalettePalReader, - 'txt' : ns.reader.PaletteTxtReader, - 'img' : ns.reader.PaletteImageReader - }; - - ns.PaletteImportService = function () {}; - - ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader = this.getReader_(file, onSuccess, onError); - if (reader) { - reader.read(); - } else { - throw 'Could not find reader for file : ' + file.name; - } - }; - - ns.PaletteImportService.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.PaletteImportService.prototype.getReader_ = function (file, onSuccess, onError) { - var readerClass = this.getReaderClass_(file); - if (readerClass) { - return new readerClass(file, onSuccess, onError); - } else { - return null; - } - }; - - ns.PaletteImportService.prototype.getReaderClass_ = function (file) { - var readerClass; - if (this.isImage_(file)) { - readerClass = fileReaders.img; - } else { - var extension = this.getExtension_(file); - readerClass = fileReaders[extension]; - } - return readerClass; - }; - - ns.PaletteImportService.prototype.getExtension_ = function (file) { - var parts = file.name.split('.'); - var extension = parts[parts.length-1]; - return extension.toLowerCase(); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.addShortcuts = function (keys, callback) { - keys.forEach(function (key) { - this.addShortcut(key, callback); - }.bind(this)); - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+", - 188 : "<", - 190 : ">" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Create a Palette'), - this.toDescriptor_('</>', 'Select previous/next palette color'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} success success callback. 1st argument will be the uploaded image URL - * @param {Function} error error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, success, error) { - var data = { - data : imageData - }; - - var wrappedSuccess = function (response) { - success(Constants.IMAGE_SERVICE_GET_URL + response.responseText); - }; - - pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - // cache of current colors by history state - this.cache = {}; - this.currentColors = []; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); - - this.colorSorter = new pskl.service.color.ColorSorter(); - this.paletteService = pskl.app.paletteService; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.HISTORY_STATE_SAVED, this.updateCurrentColors_.bind(this)); - $.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.setCurrentColors = function (colors) { - var historyIndex = pskl.app.historyService.currentIndex; - this.cache[historyIndex] = colors; - if (colors.join('') !== this.currentColors.join('')) { - this.currentColors = colors; - $.publish(Events.CURRENT_COLORS_UPDATED); - } - }; - - ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); - - return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; - }; - - ns.CurrentColorsService.prototype.loadColorsFromCache_ = function () { - var historyIndex = pskl.app.historyService.currentIndex; - var colors = this.cache[historyIndex]; - if (colors) { - this.setCurrentColors(colors); - } - }; - - ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = true; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - var currentColors = this.colorSorter.sort(colorsArray); - - this.setCurrentColors(currentColors); - }; - - ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexString_(color); - frameColors[hexColor] = true; - }.bind(this)); - return frameColors; - }; - - ns.CurrentColorsService.prototype.toHexString_ = function (color) { - if (color === Constants.TRANSPARENT_COLOR) { - return color; - } else { - color = color.replace(/\s/g, ''); - var hexRe = (/^#([a-f0-9]{3}){1,2}$/i); - var rgbRe = (/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i); - if (hexRe.test(color)) { - return color.toUpperCase(); - } else if (rgbRe.test(color)) { - var exec = rgbRe.exec(color); - return pskl.utils.rgbToHex(exec[1] * 1, exec[2] * 1, exec[3] * 1); - } else { - console.error('Could not convert color to hex : ', color); - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - var isPiskel = /\.piskel$/i.test(file.name); - var isPalette = /\.(gpl|txt|pal)$/i.test(file.name); - if (isImage) { - this.readImageFile_(file); - } else if (isPiskel) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } else if (isPalette) { - pskl.app.paletteImportService.read(file, this.onPaletteLoaded_.bind(this)); - } - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.onPaletteLoaded_ = function (palette) { - pskl.app.paletteService.savePalette(palette); - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.Tool = function () { - this.toolId = "tool"; - this.helpText = "Abstract tool"; - this.tooltipDescriptors = []; - }; - - ns.Tool.prototype.getHelpText = function() { - return this.helpText; - }; - - ns.Tool.prototype.getId = function() { - return this.toolId; - }; -})();;(function () { - var ns = $.namespace('pskl.tools'); - - ns.IconMarkupRenderer = function () {}; - - ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) { - tooltipPosition = tooltipPosition || 'right'; - shortcut = shortcut ? '(' + shortcut + ')' : ''; - var tpl = pskl.utils.Template.get('drawingTool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : ['tool-icon', tool.toolId].join(' '), - toolid : tool.toolId, - title : this.getTooltipText(tool, shortcut), - tooltipposition : tooltipPosition - }); - }; - - ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) { - var descriptors = tool.tooltipDescriptors; - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : tool.getHelpText(), - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - - ns.IconMarkupRenderer.prototype.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.IconMarkupRenderer.prototype.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})();;/** - * @provide pskl.tools.drawing.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.BaseTool = function() { - pskl.tool.Tool.call(this); - this.toolId = "tool-base"; - }; - - pskl.utils.inherit(ns.BaseTool, pskl.tools.Tool); - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.tools.drawing'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [coords.col, coords.row]); - this.raiseSaveStateEvent({ - col : coords.col, - row : coords.row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.tools.drawing.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.tools.drawing"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i 0) { - var node = this; - for (var i = 0 ; i < parts.length ; i++) { - if (!node[parts[i]]) { - node[parts[i]] = {}; - } - node = node[parts[i]]; - } - } - }); - var script = createNamespace + ""; - script = script.replace(/function \(\) \{/,"").replace(/\}[^}]*$/, ""); - script = "var name = '" + name + "';" + script; - - this.runScript(script); - }; - - ns.ImageProcessor.prototype.onWorkerMessage = function (event) { - if (event.data.type === 'STEP') { - this.onStep(event); - } else if (event.data.type === 'SUCCESS') { - this.onSuccess(event); - this.worker.terminate(); - } else if (event.data.type === 'ERROR') { - this.onError(event); - this.worker.terminate(); - } - }; - - ns.ImageProcessor.prototype.importAll__ = function (classToImport, classpath) { - this.createNamespace(classpath); - for (var key in classToImport) { - if (classToImport.hasOwnProperty(key)) { - this.addMethod(classToImport[key], classpath + '.' + key); - } - } - }; - - ns.ImageProcessor.prototype.addMethod__ = function (method, name) { - this.runScript(name + "=" + method); - }; - - ns.ImageProcessor.prototype.runScript__ = function (script) { - this.worker.postMessage({ - type : 'RUN_SCRIPT', - script : this.getScriptAsUrl(script) - }); - }; - - ns.ImageProcessor.prototype.getScriptAsUrl__ = function (script) { - var blob = new Blob([script], {type: "application/javascript"}); // pass a useful mime type here - return window.URL.createObjectURL(blob); - }; -})(); - - - -;/** - * @require Constants - * @require Events - */ -(function () { - var ns = $.namespace("pskl"); - /** - * Main application controller - */ - ns.app = { - - init : function () { - /** - * When started from APP Engine, appEngineToken_ (Boolean) should be set on window.pskl - */ - this.isAppEngineVersion = !!pskl.appEngineToken_; - - this.shortcutService = new pskl.service.keyboard.ShortcutService(); - this.shortcutService.init(); - - var size = { - height : Constants.DEFAULT.HEIGHT, - width : Constants.DEFAULT.WIDTH - }; - - var descriptor = new pskl.model.piskel.Descriptor('New Piskel', ''); - var piskel = new pskl.model.Piskel(size.width, size.height, descriptor); - - var layer = new pskl.model.Layer("Layer 1"); - var frame = new pskl.model.Frame(size.width, size.height); - - layer.addFrame(frame); - piskel.addLayer(layer); - - this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel); - this.corePiskelController.init(); - - this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); - this.piskelController.init(); - - this.paletteImportService = new pskl.service.palette.PaletteImportService(); - this.paletteService = new pskl.service.palette.PaletteService(); - this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette()); - - this.paletteController = new pskl.controller.PaletteController(); - this.paletteController.init(); - - this.currentColorsService = new pskl.service.CurrentColorsService(this.piskelController); - this.currentColorsService.init(); - - this.palettesListController = new pskl.controller.PalettesListController(this.paletteController, this.currentColorsService); - this.palettesListController.init(); - - this.cursorCoordinatesController = new pskl.controller.CursorCoordinatesController(this.piskelController); - this.cursorCoordinatesController.init(); - - this.drawingController = new pskl.controller.DrawingController(this.piskelController, this.paletteController, $('#drawing-canvas-container')); - this.drawingController.init(); - - this.previewController = new pskl.controller.preview.PreviewController(this.piskelController, $('#animated-preview-canvas-container')); - this.previewController.init(); - - this.minimapController = new pskl.controller.MinimapController(this.piskelController, this.previewController, this.drawingController, $('.minimap-container')); - this.minimapController.init(); - - this.framesListController = new pskl.controller.FramesListController(this.piskelController, $('#preview-list')); - this.framesListController.init(); - - this.layersListController = new pskl.controller.LayersListController(this.piskelController); - this.layersListController.init(); - - this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController); - this.settingsController.init(); - - this.dialogsController = new pskl.controller.dialogs.DialogsController(this.piskelController); - this.dialogsController.init(); - - this.toolController = new pskl.controller.ToolController(); - this.toolController.init(); - - this.selectionManager = new pskl.selection.SelectionManager(this.piskelController); - this.selectionManager.init(); - - this.historyService = new pskl.service.HistoryService(this.corePiskelController); - this.historyService.init(); - - this.notificationController = new pskl.controller.NotificationController(); - this.notificationController.init(); - - this.transformationsController = new pskl.controller.TransformationsController(); - this.transformationsController.init(); - - this.progressBarController = new pskl.controller.ProgressBarController(); - this.progressBarController.init(); - - this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController(); - this.canvasBackgroundController.init(); - - this.localStorageService = new pskl.service.LocalStorageService(this.piskelController); - this.localStorageService.init(); - - this.imageUploadService = new pskl.service.ImageUploadService(); - this.imageUploadService.init(); - - this.cheatsheetService = new pskl.service.keyboard.CheatsheetService(); - this.cheatsheetService.init(); - - this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController); - this.savedStatusService.init(); - - this.backupService = new pskl.service.BackupService(this.piskelController); - this.backupService.init(); - - this.beforeUnloadService = new pskl.service.BeforeUnloadService(this.piskelController); - this.beforeUnloadService.init(); - - this.fileDropperService = new pskl.service.FileDropperService(this.piskelController, $('#drawing-canvas-container').get(0)); - this.fileDropperService.init(); - - if (this.isAppEngineVersion) { - this.storageService = new pskl.service.AppEngineStorageService(this.piskelController); - } else { - this.storageService = new pskl.service.GithubStorageService(this.piskelController); - } - this.storageService.init(); - - var drawingLoop = new pskl.rendering.DrawingLoop(); - drawingLoop.addCallback(this.render, this); - drawingLoop.start(); - - this.initTooltips_(); - - var piskelData = this.getPiskelInitData_(); - if (piskelData && piskelData.piskel) { - this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); - } - - if (pskl.devtools) { - pskl.devtools.init(); - } - }, - - loadPiskel_ : function (serializedPiskel, descriptor, fps) { - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(fps); - }); - }, - - getPiskelInitData_ : function () { - return pskl.appEnginePiskelData_; - }, - - isLoggedIn : function () { - var piskelData = this.getPiskelInitData_(); - return piskelData && piskelData.isLoggedIn; - }, - - initTooltips_ : function () { - $('body').tooltip({ - selector: '[rel=tooltip]' - }); - }, - - render : function (delta) { - this.drawingController.render(delta); - this.previewController.render(delta); - this.framesListController.render(delta); - }, - - getFirstFrameAsPng : function () { - var firstFrame = this.piskelController.getFrameAt(0); - var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); - canvasRenderer.drawTransparentAs('rgba(0,0,0,0)'); - var firstFrameCanvas = canvasRenderer.render(); - return firstFrameCanvas.toDataURL("image/png"); - }, - - getFramesheetAsPng : function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - var framesheetCanvas = renderer.renderAsCanvas(); - return framesheetCanvas.toDataURL("image/png"); - } - }; -})(); - -;(function () { - var flipFrame = function (frame, horizontal, vertical) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - clone.forEachPixel(function (color, x, y) { - if (horizontal) { - x = w-x-1; - } - if (vertical) { - y = h-y-1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - }; - - window.flip = function (horizontal, vertical) { - var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex(); - var layers = pskl.app.piskelController.getLayers(); - layers.forEach(function (layer) { - flipFrame(layer.getFrameAt(currentFrameIndex), horizontal, vertical); - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - window.copyToAll = function () { - var ref = pskl.app.piskelController.getCurrentFrame(); - var layer = pskl.app.piskelController.getCurrentLayer(); - layer.getFrames().forEach(function (frame) { - if (frame !== ref) { - frame.setPixels(ref.getPixels()); - } - }); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; -})(); \ No newline at end of file diff --git a/js/piskel-packaged-2015-04-27-12-01.js b/js/piskel-packaged-2015-04-27-12-01.js deleted file mode 100644 index a5027b97..00000000 --- a/js/piskel-packaged-2015-04-27-12-01.js +++ /dev/null @@ -1,27541 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_PALETTE_COLORS : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing', - - // SERVICE URLS - APPENGINE_SAVE_URL : 'save', - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' -}; -;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : 'TOOL_SELECTED', - SELECT_TOOL : 'SELECT_TOOL', - - TOOL_RELEASED : 'TOOL_RELEASED', - TOOL_PRESSED : 'TOOL_PRESSED', - SELECT_PRIMARY_COLOR: 'SELECT_PRIMARY_COLOR', - SELECT_SECONDARY_COLOR: 'SELECT_SECONDARY_COLOR', - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: 'USER_SETTINGS_CHANGED', - - CLOSE_SETTINGS_DRAWER : 'CLOSE_SETTINGS_DRAWER', - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: 'PISKEL_RESET', - PISKEL_SAVE_STATE: 'PISKEL_SAVE_STATE', - - HISTORY_STATE_SAVED: 'HISTORY_STATE_SAVED', - HISTORY_STATE_LOADED: 'HISTORY_STATE_LOADED', - - PISKEL_SAVED: 'PISKEL_SAVED', - - FRAME_SIZE_CHANGED : 'FRAME_SIZE_CHANGED', - - SELECTION_CREATED: 'SELECTION_CREATED', - SELECTION_MOVE_REQUEST: 'SELECTION_MOVE_REQUEST', - SELECTION_DISMISSED: 'SELECTION_DISMISSED', - - SHOW_NOTIFICATION: 'SHOW_NOTIFICATION', - HIDE_NOTIFICATION: 'HIDE_NOTIFICATION', - - SHOW_PROGRESS: 'SHOW_PROGRESS', - UPDATE_PROGRESS: 'UPDATE_PROGRESS', - HIDE_PROGRESS: 'HIDE_PROGRESS', - - ZOOM_CHANGED : 'ZOOM_CHANGED', - - CURRENT_COLORS_UPDATED : 'CURRENT_COLORS_UPDATED', - - MOUSE_EVENT : 'MOUSE_EVENT', - - // Tests - TEST_RECORD_END : 'TEST_RECORD_END', - TEST_CASE_END : 'TEST_CASE_END', - TEST_SUITE_END : 'TEST_SUITE_END' -}; -;jQuery.namespace = function() { - var a = arguments; - var o = null; - for (var i = 0; i < a.length ; i++) { - var d = a[i].split('.'); - o = window; - for (var j = 0 ; j < d.length ; j++) { - o[d[j]] = o[d[j]] || {}; - o = o[d[j]]; - } - } - return o; -}; - -/** - * Need a polyfill for PhantomJS - */ -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var bindArgs = Array.prototype.slice.call(arguments, 1); - var fToBind = this; - var fNOP = function () {}; - var fBound = function () { - var args = bindArgs.concat(Array.prototype.slice.call(arguments)); - return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, args); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -/** - * @provide pskl.utils - * - * @require Constants - */ -(function() { // namespace: pskl.utils - - var ns = $.namespace('pskl.utils'); - - /** - * Convert a rgb(Number, Number, Number) color to hexadecimal representation - * @param {Number} r red value, between 0 and 255 - * @param {Number} g green value, between 0 and 255 - * @param {Number} b blue value, between 0 and 255 - * @return {String} hex representation of the color '#ABCDEF' - */ - ns.rgbToHex = function (r, g, b) { - return '#' + pskl.utils.componentToHex(r) + pskl.utils.componentToHex(g) + pskl.utils.componentToHex(b); - }; - - /** - * Convert a color component (as a Number between 0 and 255) to its string hexa representation - * @param {Number} c component value, between 0 and 255 - * @return {String} eg. '0A' - */ - ns.componentToHex = function (c) { - var hex = c.toString(16); - return hex.length == 1 ? '0' + hex : hex; - }; - - ns.normalize = function (value, def) { - if (typeof value === 'undefined' || value === null) { - return def; - } else { - return value; - } - }; - - ns.inherit = function(extendedObject, inheritFrom) { - extendedObject.prototype = Object.create(inheritFrom.prototype); - extendedObject.prototype.constructor = extendedObject; - extendedObject.prototype.superclass = inheritFrom.prototype; - }; - - ns.wrap = function (wrapper, wrappedObject) { - for (var prop in wrappedObject) { - if (typeof wrappedObject[prop] === 'function' && typeof wrapper[prop] === 'undefined') { - wrapper[prop] = wrappedObject[prop].bind(wrappedObject); - } - } - }; - - ns.hashCode = function(str) { - var hash = 0; - if (str.length !== 0) { - for (var i = 0, l = str.length; i < l; i++) { - var chr = str.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; - hash |= 0; // Convert to 32bit integer - } - } - return hash; - }; - - ns.copy = function (object) { - return JSON.parse(JSON.stringify(object)); - }; - - var entityMap = { - '&' : '&', - '<' : '<', - '>' : '>', - '"' : '"', - '\'': ''', - '/' : '/' - }; - ns.escapeHtml = function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml = function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], 'g'); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test(ua), - isIE11 : /trident/i.test(ua), - isChrome : /Chrome/i.test(ua), - isFirefox : /Firefox/i.test(ua), - isMac : /Mac/.test(ua) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec(ua)[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec(ua)[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec(ua)[1], 10); - } - })(); -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Array = { - find : function (array, filterFn) { - var match = null; - array = Array.isArray(array) ? array : []; - var filtered = array.filter(filterFn); - if (filtered.length) { - match = filtered[0]; - } - return match; - } - }; - -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var base64Ranks; - if (Uint8Array) { - base64Ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/, '')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length; - var i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64Ranks[code - 43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var headerEnd = dataURI.indexOf(','); - var data = dataURI.substring(headerEnd + 1); - var isBase64 = BASE64_REGEX.test(dataURI.substring(0, headerEnd)); - var blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? 'base64' : 'URI'; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function (canvas, callback, type /*, ...args*/) { - type = type || 'image/png'; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile('canvas', type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || 'text/plain'; - pskl.utils.BlobUtils.dataToBlob('data:' + type + ',' + string, type, callback); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement('canvas'); - canvas.setAttribute('width', width); - canvas.setAttribute('height', height); - - if (typeof classList == 'string') { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.utils.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.utils.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, false); - }, - - enableImageSmoothing : function (canvas) { - pskl.utils.CanvasUtils.setImageSmoothing(canvas, true); - }, - - setImageSmoothing : function (canvas, smoothing) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = smoothing; - context.mozImageSmoothingEnabled = smoothing; - context.oImageSmoothingEnabled = smoothing; - context.webkitImageSmoothingEnabled = smoothing; - context.msImageSmoothingEnabled = smoothing; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.utils.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || 'png'; - var data = canvas.toDataURL('image/' + format); - return data.substr(data.indexOf(',') + 1); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ColorUtils = { - getUnusedColor : function (usedColors) { - usedColors = usedColors || []; - // create check map - var colorMap = {}; - usedColors.forEach(function (color) { - colorMap[color.toUpperCase()] = true; - }); - - // start with white - var color = { - r : 255, - g : 255, - b : 255 - }; - var match = null; - while (true) { - var hex = window.tinycolor(color).toHexString().toUpperCase(); - - if (!colorMap[hex]) { - match = hex; - break; - } else { - // pick a non null component to decrease its value - var component = (color.r && 'r') || (color.g && 'g') || (color.b && 'b'); - if (component) { - color[component] = color[component] - 1; - } else { - // no component available, no match found - break; - } - } - } - - return match; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return '0' + num; - } else { - return '' + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Event = {}; - - ns.Event.addEventListener = function (el, type, callback, scope, args) { - if (typeof el === 'string') { - el = document.querySelector(el); - } - - var listener = { - el : el, - type : type, - callback : callback, - handler : args ? callback.bind(scope, args) : callback.bind(scope) - }; - - scope.__pskl_listeners = scope.__pskl_listeners || []; - scope.__pskl_listeners.push(listener); - el.addEventListener(type, listener.handler); - }; - - ns.Event.removeEventListener = function (el, type, callback, scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - if (listener.callback === callback && listener.el === el && listener.type === type) { - el.removeEventListener(type, listeners[i].handler); - listeners.splice(i, 1); - break; - } - } - } - }; - - ns.Event.removeAllEventListeners = function (scope) { - if (scope && scope.__pskl_listeners) { - var listeners = scope.__pskl_listeners; - for (var i = 0 ; i < listeners.length ; i++) { - var listener = listeners[i]; - listener.el.removeEventListener(listener.type, listener.handler); - } - scope.__pskl_listeners = []; - } - }; -})(); -;/** - * detection method from: - * http://videlais.com/2014/08/23/lessons-learned-from-detecting-node-webkit/ - */ - -(function () { - - var ns = $.namespace('pskl.utils'); - - ns.Environment = { - detectNodeWebkit : function () { - var isNode = (typeof window.process !== 'undefined' && typeof window.require !== 'undefined'); - var isNodeWebkit = false; - if (isNode) { - try { - isNodeWebkit = (typeof window.require('nw.gui') !== 'undefined'); - } catch (e) { - isNodeWebkit = false; - } - } - return isNodeWebkit; - } - }; - -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function (event) { - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - var CONFIRM_OVERRIDE = 'File already exists, do you want to override it ?'; - - ns.FileUtilsDesktop = { - - chooseFileDialog: function (callback) { - var tagString = ''; - var $chooser = $(tagString); - $chooser.change(function (e) { - var filename = $(this).val(); - callback(filename); - }); - $chooser.trigger('click'); - }, - - addExtensionIfNeeded : function (filename, extension) { - if (typeof extension == 'string') { - if (extension[0] !== '.') { - extension = '.' + extension; - } - var hasExtension = (filename.substring(filename.length - extension.length) === extension); - if (!hasExtension) { - filename += extension; - } - } - return filename; - }, - - /** - * - * @param content - * @param defaultFilename - file name to pre-populate the dialog - * @param extension - if supplied, the selected extension will guaranteed to be on the filename - - * NOTE: there is a possible danger here... If the extension is added to a fileName, but there - * is already another file of the same name *with* the extension, it will get overwritten. - * @param callback - */ - saveAs: function (content, defaultFilename, extension, callback) { - // NodeWebkit has no js api for opening the save dialog. - // Instead, it adds two new attributes to the anchor tag: nwdirectory and nwsaveas - // (see: https://github.com/nwjs/nw.js/wiki/File-dialogs ) - defaultFilename = defaultFilename || 'New Piskel'; - defaultFilename = pskl.utils.FileUtilsDesktop.addExtensionIfNeeded(defaultFilename, extension); - var tagString = ''; - var $chooser = $(tagString); - $chooser.change(function (e) { - var filename = $(this).val(); - filename = pskl.utils.FileUtilsDesktop.addExtensionIfNeeded(filename, extension); - pskl.utils.FileUtilsDesktop.saveToFile(content, filename, function () { - callback(filename); - }); - }); - - $chooser.trigger('click'); - }, - - /** - * Save data directly to disk, without showing a save dialog - * Requires Node-Webkit environment for file system access - * @param content - data to be saved - * @param {string} filename - fill path to the file - * @callback callback - */ - saveToFile : function(content, filename, callback) { - var fs = window.require('fs'); - fs.writeFile(filename, content, function (err) { - if (err) { - //throw err; - console.log('FileUtilsDesktop::savetoFile() - error saving file:', filename, 'Error:', err); - } - callback(); - }); - }, - - readFile : function(filename, callback) { - var fs = window.require('fs'); - // NOTE: currently loading everything as utf8, which may not be desirable in future - fs.readFile(filename, 'utf8', function (err, data) { - if (err) { - console.log('FileUtilsDesktop::readFile() - error reading file:', filename, 'Error:', err); - } - callback(data); - }); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.FrameTransform = { - VERTICAL : 'vertical', - HORIZONTAL : 'HORIZONTAL', - flip : function (frame, axis) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - clone.forEachPixel(function (color, x, y) { - if (axis === ns.FrameTransform.VERTICAL) { - x = w - x - 1; - } else if (axis === ns.FrameTransform.HORIZONTAL) { - y = h - y - 1; - } - frame.pixels[x][y] = color; - }); - frame.version++; - return frame; - }, - - CLOCKWISE : 'clockwise', - COUNTERCLOCKWISE : 'counterclockwise', - rotate : function (frame, direction) { - var clone = frame.clone(); - var w = frame.getWidth(); - var h = frame.getHeight(); - - var max = Math.max(w, h); - var xDelta = Math.ceil((max - w) / 2); - var yDelta = Math.ceil((max - h) / 2); - - frame.forEachPixel(function (color, x, y) { - var _x = x; - var _y = y; - - // Convert to square coords - x = x + xDelta; - y = y + yDelta; - - // Perform the rotation - var tmpX = x; - var tmpY = y; - if (direction === ns.FrameTransform.CLOCKWISE) { - x = tmpY; - y = max - 1 - tmpX; - } else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) { - y = tmpX; - x = max - 1 - tmpY; - } - - // Convert the coordinates back to the rectangular grid - x = x - xDelta; - y = y - yDelta; - if (clone.containsPixel(x, y)) { - frame.pixels[_x][_y] = clone.getPixel(x, y); - } else { - frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR; - } - }); - frame.version++; - return frame; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - /** - * Render a Frame object as an image. - * Can optionally scale it (zoom) - * @param {Frame} frame - * @param {Number} zoom - * @return {Image} - */ - toImage : function (frame, zoom) { - zoom = zoom || 1; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }, - - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (color, col, row) { - if (color != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, color); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width; - var h = image.height; - var canvas = pskl.utils.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0, 0, w, h, 0, 0, w, h); - var imgData = context.getImageData(0, 0, w, h).data; - return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); - }, - - createFromImageData_ : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++) { - grid[x] = []; - for (var y = 0 ; y < height ; y++) { - // Find the starting index in the one-dimensional image data - var i = (y * width + x) * 4; - var r = imageData[i ]; - var g = imageData[i + 1]; - var b = imageData[i + 2]; - var a = imageData[i + 3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.rgbToHex(r, g, b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels__ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a) | 0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a) | 0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a) | 0; - - return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba__ : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createLayerFromSpritesheet : function (image, frameCount) { - var width = image.width; - var height = image.height; - var frameWidth = width / frameCount; - - var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, height); - var context = canvas.getContext('2d'); - - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - context.clearRect(0, 0 , frameWidth, height); - context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); - var frame = pskl.utils.FrameUtils.createFromImage(canvas); - frames.push(frame); - } - return frames; - }, - - mergeLayers : function (layerA, layerB) { - var framesA = layerA.getFrames(); - var framesB = layerB.getFrames(); - var mergedFrames = []; - framesA.forEach(function (frame, index) { - var otherFrame = framesB[index]; - mergedFrames.push(pskl.utils.FrameUtils.merge([otherFrame, frame])); - }); - var mergedLayer = pskl.model.Layer.fromFrames(layerA.getName(), mergedFrames); - return mergedLayer; - } - }; - -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.utils.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.utils.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.utils.CanvasUtils.createCanvas(zoom * source.width, zoom * source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.utils.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}; - var xOffset = 0; - var yOffset = 0; - - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - var xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + '']) { - // Cache Y Range - yRanges[y + ''] = Math.floor((y + 1) * zoom) - yOffset; - } - var yRange = yRanges[y + '']; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + (a / 255) + ')'; - context.fillRect(xOffset, yOffset, xRange - margin, yRange - margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl'); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for (var x = rectangle.x0 ; x <= rectangle.x1 ; x++) { - for (var y = rectangle.y0 ; y <= rectangle.y1 ; y++) { - pixels.push({'col': x, 'row': y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for (var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({'col': x, 'row': rectangle.y0}); - pixels.push({'col': x, 'row': rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for (var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({'col': rectangle.x0, 'row': y}); - pixels.push({'col': rectangle.x1, 'row': y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = 'sdfsdfsdf'; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch (e) { - // Frame out of bound exception. - } - - if (targetColor == replacementColor) { - return; - } - - queue.push({'col': col, 'row': row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while (queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({'col': currentItem.col, 'row': currentItem.row}); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({'col': nextCol, 'row': nextRow}); - } - } catch (e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if (loopCount > 10 * cellCount) { - console.log('loop breaker called'); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - ns.PiskelFileUtils.decodePiskelFile( - rawPiskel, - function (piskel, descriptor, fps) { - // if using Node-Webkit, store the savePath on load - // Note: the 'path' property is unique to Node-Webkit, and holds the full path - if (pskl.utils.Environment.detectNodeWebkit()) { - piskel.savePath = file.path; - } - onSuccess(piskel, descriptor, fps); - }, - onError - ); - }); - }, - - decodePiskelFile : function (rawPiskel, onSuccess, onError) { - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var piskel = serializedPiskel.piskel; - var descriptor = new pskl.model.piskel.Descriptor(piskel.name, piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - } - - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error('Could not find template for id :', templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement('div'); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - insert : function (parent, position, templateId, dict) { - var html = pskl.utils.Template.getAndReplace(templateId, dict); - parent.insertAdjacentHTML(position, html); - }, - - getAndReplace : function (templateId, dict) { - var result = ''; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{' + key + '\\}\\}', 'g'), value); - } - } - return template; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.TooltipFormatter = {}; - - ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) { - var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template'); - return pskl.utils.Template.replace(tpl, { - helptext : helpText, - shortcut : shortcut, - descriptors : this.formatToolDescriptors_(descriptors) - }); - }; - - ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) { - descriptors = descriptors || []; - return descriptors.reduce(function (p, descriptor) { - return p += this.formatToolDescriptor_(descriptor); - }.bind(this), ''); - }; - - ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; -})(); -;(function () { - var ns = $.namespace('pskl'); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - MAX_FPS : 'MAX_FPS', - DEFAULT_SIZE : 'DEFAULT_SIZE', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'MAX_FPS' : 24, - 'DEFAULT_SIZE' : { - width : Constants.DEFAULT.WIDTH, - height : Constants.DEFAULT.HEIGHT - }, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != 'undefined') { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - var isValidKey = key in this.KEY_TO_DEFAULT_VALUE_MAP_; - if (!isValidKey) { - console.error('UserSettings key <' + key + '> not found in supported keys.'); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - var workers = {}; - - ns.WorkerUtils = { - createWorker : function (worker, workerId) { - if (!workers[workerId]) { - workers[workerId] = ns.WorkerUtils.createWorkerURL(worker); - } - - return new Worker(workers[workerId]); - }, - - createWorkerURL : function (worker) { - // remove "function () {" at the start of the worker string and the last "}" before the end - var typedArray = [(worker + '').replace(/function\s*\(\)\s*\{/, '').replace(/\}[^}]*$/, '')]; - var blob = new Blob(typedArray, {type: 'application/javascript'}); - return window.URL.createObjectURL(blob); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function () {}; - error = error || function () {}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function (e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function (e) { - error(e, this); - }; - - return xhr; - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})(); -;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var step_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - step_callback = callback.step; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - if (!flat) { - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - } - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;// vim:ts=4:sts=4:sw=4: -/*! - * - * Copyright 2009-2012 Kris Kowal under the terms of the MIT - * license found at http://github.com/kriskowal/q/raw/master/LICENSE - * - * With parts by Tyler Close - * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found - * at http://www.opensource.org/licenses/mit-license.html - * Forked at ref_send.js version: 2009-05-11 - * - * With parts by Mark Miller - * Copyright (C) 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -(function (definition) { - "use strict"; - - // This file will function properly as a - - - - -
        - - -
        -
        - -
        - -
        -
        -
        -
        -
        - -
        - - - -
        -
        -
        - -
        -
        - -
        -
        - - - - - -
        -
        -
        -
        -
        - -
        -
        - - - -
        -
        - - - - - - - - - diff --git a/palettes-proto/js/lib/gif/gif.ie.worker.js b/palettes-proto/js/lib/gif/gif.ie.worker.js deleted file mode 100644 index 675f9d5e..00000000 --- a/palettes-proto/js/lib/gif/gif.ie.worker.js +++ /dev/null @@ -1 +0,0 @@ -(function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<{iframe-content} - * The content can later be accessed by getting the script (through getElementById for instance) and reading innerHTML - * @param {HTMLElement} iframe - */ - var storeFrame = function (iframe) { - var script=document.createElement("script"); - script.setAttribute("type", "text/html"); - script.setAttribute("id", iframe.getAttribute("src").replace(/.*templates[^\/]*\//,'templates/')); - script.innerHTML = iframe.contentWindow.document.body.innerHTML; - iframe.parentNode.removeChild(iframe); - document.body.appendChild(script); - }; - - window.iframeloader = { - onLoad : function (event) { - var iframe = event.target || event.srcElement; - processFrame(iframe); - } - }; -})(); \ No newline at end of file diff --git a/palettes-proto/js/piskel-packaged-2014-09-07-07-04.js b/palettes-proto/js/piskel-packaged-2014-09-07-07-04.js deleted file mode 100644 index 4109e03c..00000000 --- a/palettes-proto/js/piskel-packaged-2014-09-07-07-04.js +++ /dev/null @@ -1,23103 +0,0 @@ -/*! - * jQuery JavaScript Library v1.8.0 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) - */ -(function( window, undefined ) { -var - // A central reference to the root jQuery(document) - rootjQuery, - - // The deferred used on DOM ready - readyList, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - navigator = window.navigator, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Save a reference to some core methods - core_push = Array.prototype.push, - core_slice = Array.prototype.slice, - core_indexOf = Array.prototype.indexOf, - core_toString = Object.prototype.toString, - core_hasOwn = Object.prototype.hasOwnProperty, - core_trim = String.prototype.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, - - // Used for detecting and trimming whitespace - core_rnotwhite = /\S/, - core_rspace = /\s+/, - - // IE doesn't match non-breaking spaces with \s - rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return ( letter + "" ).toUpperCase(); - }, - - // The ready event handler and self cleanup method - DOMContentLoaded = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - } else if ( document.readyState === "complete" ) { - // we're here because readyState === "complete" in oldIE - // which is good enough for us to call the dom ready! - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = ( context && context.nodeType ? context.ownerDocument || context : document ); - - // scripts is true for back-compat - selector = jQuery.parseHTML( match[1], doc, true ); - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - this.attr.call( selector, context, true ); - } - - return jQuery.merge( this, selector ); - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.8.0", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - eq: function( i ) { - i = +i; - return i === -1 ? - this.slice( i ) : - this.slice( i, i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ), - "slice", core_slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ core_toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // scripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, scripts ) { - var parsed; - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - scripts = context; - context = 0; - } - context = context || document; - - // Single tag - if ( (parsed = rsingleTag.exec( data )) ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); - return jQuery.merge( [], - (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); - }, - - parseJSON: function( data ) { - if ( !data || typeof data !== "string") { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && core_rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var name, - i = 0, - length = obj.length, - isObj = length === undefined || jQuery.isFunction( obj ); - - if ( args ) { - if ( isObj ) { - for ( name in obj ) { - if ( callback.apply( obj[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( obj[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in obj ) { - if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var type, - ret = results || []; - - if ( arr != null ) { - // The window, strings (and functions) also have 'length' - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - type = jQuery.type( arr ); - - if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { - core_push.call( ret, arr ); - } else { - jQuery.merge( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, - ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, pass ) { - var exec, - bulk = key == null, - i = 0, - length = elems.length; - - // Sets many values - if ( key && typeof key === "object" ) { - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); - } - chainable = 1; - - // Sets one value - } else if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = pass === undefined && jQuery.isFunction( value ); - - if ( bulk ) { - // Bulk operations only iterate when executing function values - if ( exec ) { - exec = fn; - fn = function( elem, key, value ) { - return exec.call( jQuery( elem ), value ); - }; - - // Otherwise they run against the entire set - } else { - fn.call( elems, value ); - fn = null; - } - } - - if ( fn ) { - for (; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - } - - chainable = 1; - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready, 1 ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.split( core_rspace ), function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // Flag to know if list is currently firing - firing, - // First callback to fire (used internally by add and fireWith) - firingStart, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { - list.push( arg ); - } else if ( arg && arg.length ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Control if a given callback is in the list - has: function( fn ) { - return jQuery.inArray( fn, list ) > -1; - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? - function() { - var returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - } : - newDefer[ action ] - ); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] = list.fire - deferred[ tuple[0] ] = list.fire; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, - all, - a, - select, - opt, - input, - fragment, - eventName, - i, - isSupported, - clickFn, - div = document.createElement("div"); - - // Preliminary tests - div.setAttribute( "className", "t" ); - div.innerHTML = "
         
        a"; - - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: ( document.compatMode === "CSS1Compat" ), - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", clickFn = function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent("onclick"); - div.detachEvent( "onclick", clickFn ); - } - - // Check if a radio maintains its value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - input.setAttribute( "checked", "checked" ); - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.lastChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - fragment.removeChild( input ); - fragment.appendChild( div ); - - // Technique from Juriy Zaytsev - // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for ( i in { - submit: true, - change: true, - focusin: true - }) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Run tests that need a body at doc ready - jQuery(function() { - var container, div, tds, marginDiv, - divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; - body.insertBefore( container, body.firstChild ); - - // Construct the test element - div = document.createElement("div"); - container.appendChild( div ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE <= 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // NOTE: To any future maintainer, window.getComputedStyle was used here - // instead of getComputedStyle because it gave a better gzip size. - // The difference between window.getComputedStyle and getComputedStyle is - // 7 bytes - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = document.createElement("div"); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== "undefined" ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = "block"; - div.style.overflow = "visible"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - container.style.zoom = 1; - } - - // Null elements to avoid leaks in IE - body.removeChild( container ); - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - fragment.removeChild( div ); - all = a = select = opt = input = fragment = div = null; - - return support; -})(); -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; - -jQuery.extend({ - cache: {}, - - deletedIds: [], - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, l, - - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var parts, part, attr, name, l, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attr = elem.attributes; - for ( l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - parts = key.split( ".", 2 ); - parts[1] = parts[1] ? "." + parts[1] : ""; - part = parts[1] + "!"; - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - data = this.triggerHandler( "getData" + part, [ parts[0] ] ); - - // Try to fetch any internally stored data first - if ( data === undefined && elem ) { - data = jQuery.data( elem, key ); - data = dataAttr( elem, key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } - - parts[1] = value; - this.each(function() { - var self = jQuery( this ); - - self.triggerHandler( "setData" + part, parts ); - jQuery.data( this, key, value ); - self.triggerHandler( "changeData" + part, parts ); - }); - }, null, value, arguments.length > 1, null, false ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - if ( !queue.length && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery.removeData( elem, type + "queue", true ); - jQuery.removeData( elem, key, true ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, fixSpecified, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea|)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var removes, className, elem, c, cl, i, l; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - if ( (value && typeof value === "string") || value === undefined ) { - removes = ( value || "" ).split( core_rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - if ( elem.nodeType === 1 && elem.className ) { - - className = (" " + elem.className + " ").replace( rclass, " " ); - - // loop over each item in the removal list - for ( c = 0, cl = removes.length; c < cl; c++ ) { - // Remove until there is nothing to remove, - while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { - className = className.replace( " " + removes[ c ] + " " , " " ); - } - } - elem.className = value ? jQuery.trim( className ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( core_rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, i, max, option, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - i = one ? index : 0; - max = one ? index + 1 : options.length; - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 - attrFn: {}, - - attr: function( elem, name, value, pass ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var propName, attrNames, name, isBool, - i = 0; - - if ( value && elem.nodeType === 1 ) { - - attrNames = value.split( core_rspace ); - - for ( ; i < attrNames.length; i++ ) { - name = attrNames[ i ]; - - if ( name ) { - propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); - - // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { - jQuery.attr( elem, name, "" ); - } - elem.removeAttribute( getSetAttribute ? name : propName ); - - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } - } - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - // Use the value property for back compat - // Use the nodeHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { - return nodeHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - fixSpecified = { - name: true, - id: true, - coords: true - }; - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - ret = document.createAttribute( name ); - elem.setAttributeNode( ret ); - } - return ( ret.value = value + "" ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - if ( value === "" ) { - value = "false"; - } - nodeHook.set( elem, value, name ); - } - }; -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = "" + value ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:textarea|input|select)$/i, - rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, - rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - hoverHack = function( events ) { - return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); - }; - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - add: function( elem, types, handler, data, selector ) { - - var elemData, eventHandle, events, - t, tns, type, namespaces, handleObj, - handleObjIn, handlers, special; - - // Don't attach events to noData or text/comment nodes (allow plain objects tho) - if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - events = elemData.events; - if ( !events ) { - elemData.events = events = {}; - } - eventHandle = elemData.handle; - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = jQuery.trim( hoverHack(types) ).split( " " ); - for ( t = 0; t < types.length; t++ ) { - - tns = rtypenamespace.exec( types[t] ) || []; - type = tns[1]; - namespaces = ( tns[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: tns[1], - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - handlers = events[ type ]; - if ( !handlers ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var t, tns, type, origType, namespaces, origCount, - j, events, special, eventType, handleObj, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = jQuery.trim( hoverHack( types || "" ) ).split(" "); - for ( t = 0; t < types.length; t++ ) { - tns = rtypenamespace.exec( types[t] ) || []; - type = origType = tns[1]; - namespaces = tns[2]; - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector? special.delegateType : special.bindType ) || type; - eventType = events[ type ] || []; - origCount = eventType.length; - namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - - // Remove matching events - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !namespaces || namespaces.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - eventType.splice( j--, 1 ); - - if ( handleObj.selector ) { - eventType.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( eventType.length === 0 && origCount !== eventType.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery.removeData( elem, "events", true ); - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Don't do events on text and comment nodes - if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { - return; - } - - // Event object or event type - var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, - type = event.type || event, - namespaces = []; - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "!" ) >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf( "." ) >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.isTrigger = true; - event.exclusive = exclusive; - event.namespace = namespaces.join( "." ); - event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; - ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; - - // Handle a global trigger - if ( !elem ) { - - // TODO: Stop taunting the data cache; remove global events and always attach to document - cache = jQuery.cache; - for ( i in cache ) { - if ( cache[ i ].events && cache[ i ].events[ type ] ) { - jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); - } - } - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - eventPath = [[ elem, special.bindType || type ]]; - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; - for ( old = elem; cur; cur = cur.parentNode ) { - eventPath.push([ cur, bubbleType ]); - old = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( old === (elem.ownerDocument || document) ) { - eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); - } - } - - // Fire handlers on the event path - for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - - cur = eventPath[i][0]; - event.type = eventPath[i][1]; - - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - // Note that this is a bare JS function and not a jQuery handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - // IE<9 dies on focus/blur to hidden element (#1486) - if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( old ) { - elem[ ontype ] = old; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event || window.event ); - - var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, - handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), - delegateCount = handlers.delegateCount, - args = [].slice.call( arguments ), - run_all = !event.exclusive && !event.namespace, - special = jQuery.event.special[ event.type ] || {}, - handlerQueue = []; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers that should run if there are delegated events - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && !(event.button && event.type === "click") ) { - - // Pregenerate a single jQuery object for reuse with .is() - jqcur = jQuery(this); - jqcur.context = this; - - for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - - // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) - if ( cur.disabled !== true || event.type !== "click" ) { - selMatch = {}; - matches = []; - jqcur[0] = cur; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - sel = handleObj.selector; - - if ( selMatch[ sel ] === undefined ) { - selMatch[ sel ] = jqcur.is( sel ); - } - if ( selMatch[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, matches: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( handlers.length > delegateCount ) { - handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); - } - - // Run delegates first; they may want to stop propagation beneath us - for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { - matched = handlerQueue[ i ]; - event.currentTarget = matched.elem; - - for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { - handleObj = matched.matches[ j ]; - - // Triggered event must either 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { - - event.data = handleObj.data; - event.handleObj = handleObj; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** - props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, - originalEvent = event, - fixHook = jQuery.event.fixHooks[ event.type ] || {}, - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = jQuery.Event( originalEvent ); - - for ( i = copy.length; i; ) { - prop = copy[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Target should not be a text node (#504, Safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) - event.metaKey = !!event.metaKey; - - return fixHook.filter? fixHook.filter( event, originalEvent ) : event; - }, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady - }, - - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - - focus: { - delegateType: "focusin" - }, - blur: { - delegateType: "focusout" - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -// Some plugins are using, but it's undocumented/deprecated and will be removed. -// The 1.7 special event interface should provide all the hooks needed now. -jQuery.event.handle = jQuery.event.dispatch; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 – - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj, - selector = handleObj.selector; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "_submit_attached" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "_submit_attached", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "_change_attached", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { // && selector != null - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - live: function( types, data, fn ) { - jQuery( this.context ).on( types, this.selector, data, fn ); - return this; - }, - die: function( types, fn ) { - jQuery( this.context ).off( types, this.selector || "**", fn ); - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; - - if ( rkeyEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; - } - - if ( rmouseEvent.test( name ) ) { - jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var cachedruns, - dirruns, - sortOrder, - siblingCheck, - assertGetIdNotName, - - document = window.document, - docElem = document.documentElement, - - strundefined = "undefined", - hasDuplicate = false, - baseHasDuplicate = true, - done = 0, - slice = [].slice, - push = [].push, - - expando = ( "sizcache" + Math.random() ).replace( ".", "" ), - - // Regex - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", - pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", - combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", - groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcombinators = new RegExp( "^" + combinators ), - - // All simple (non-comma) selectors, excluding insignifant trailing whitespace - rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), - - // A selector, or everything after leading whitespace - // Optionally followed in either case by a ")" for terminating sub-selectors - rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), - - // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive - rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - rendsWithNot = /:not\($/, - - rheader = /h\d/i, - rinputs = /input|select|textarea|button/i, - - rbackslash = /\\(?!\\)/g, - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "POS": new RegExp( pos, "ig" ), - // For use in libraries implementing .is() - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) - }, - - classCache = {}, - cachedClasses = [], - compilerCache = {}, - cachedSelectors = [], - - // Mark a function for use in filtering - markFunction = function( fn ) { - fn.sizzleFilter = true; - return fn; - }, - - // Returns a function to use in pseudos for input types - createInputFunction = function( type ) { - return function( elem ) { - // Check the input's nodeName and type - return elem.nodeName.toLowerCase() === "input" && elem.type === type; - }; - }, - - // Returns a function to use in pseudos for buttons - createButtonFunction = function( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; - }, - - // Used for testing something on an element - assert = function( fn ) { - var pass = false, - div = document.createElement("div"); - try { - pass = fn( div ); - } catch (e) {} - // release memory in IE - div = null; - return pass; - }, - - // Check if attributes should be retrieved by attribute nodes - assertAttributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }), - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - assertUsableName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = document.getElementsByName && - // buggy browsers will return fewer than the correct 2 - document.getElementsByName( expando ).length === - // buggy browsers will return more than the correct 0 - 2 + document.getElementsByName( expando + 0 ).length; - assertGetIdNotName = !document.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }), - - // Check if the browser returns only elements - // when doing getElementsByTagName("*") - assertTagNameNoComments = assert(function( div ) { - div.appendChild( document.createComment("") ); - return div.getElementsByTagName("*").length === 0; - }), - - // Check if getAttribute returns normalized href attributes - assertHrefNotNormalized = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }), - - // Check if getElementsByClassName can be trusted - assertUsableClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return false; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length !== 1; - }); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - var match, elem, xml, m, - nodeType = context.nodeType; - - if ( nodeType !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - xml = isXML( context ); - - if ( !xml && !seed ) { - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - } - - // All others - return select( selector, context, results, seed, xml ); -}; - -var Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - match: matchExpr, - - order: [ "ID", "TAG" ], - - attrHandle: {}, - - createPseudo: markFunction, - - find: { - "ID": assertGetIdNotName ? - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - } : - function( id, context, xml ) { - if ( typeof context.getElementById !== strundefined && !xml ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }, - - "TAG": assertTagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - var elem, - tmp = [], - i = 0; - - for ( ; (elem = results[i]); i++ ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - } - }, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( rbackslash, "" ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr.CHILD - 1 type (only|nth|...) - 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 3 xn-component of xn+y argument ([+-]?\d*n|) - 4 sign of xn-component - 5 x of xn-component - 6 sign of y-component - 7 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1] === "nth" ) { - // nth-child requires argument - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); - match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); - - // other types prohibit arguments - } else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var argument, - unquoted = match[4]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Relinquish our claim on characters in `unquoted` from a closing parenthesis on - if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { - - match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); - unquoted = argument[0].slice( 0, -1 ); - } - - // Quoted or unquoted, we have the full argument - // Return only captures needed by the pseudo filter method (type and argument) - match.splice( 2, 3, unquoted || match[3] ); - return match; - } - }, - - filter: { - "ID": assertGetIdNotName ? - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - return elem.getAttribute("id") === id; - }; - } : - function( id ) { - id = id.replace( rbackslash, "" ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === id; - }; - }, - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); - - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className ]; - if ( !pattern ) { - pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); - cachedClasses.push( className ); - // Avoid too large of a cache - if ( cachedClasses.length > Expr.cacheLength ) { - delete classCache[ cachedClasses.shift() ]; - } - } - return function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }; - }, - - "ATTR": function( name, operator, check ) { - if ( !operator ) { - return function( elem ) { - return Sizzle.attr( elem, name ) != null; - }; - } - - return function( elem ) { - var result = Sizzle.attr( elem, name ), - value = result + ""; - - if ( result == null ) { - return operator === "!="; - } - - switch ( operator ) { - case "=": - return value === check; - case "!=": - return value !== check; - case "^=": - return check && value.indexOf( check ) === 0; - case "*=": - return check && value.indexOf( check ) > -1; - case "$=": - return check && value.substr( value.length - check.length ) === check; - case "~=": - return ( " " + value + " " ).indexOf( check ) > -1; - case "|=": - return value === check || value.substr( 0, check.length + 1 ) === check + "-"; - } - }; - }, - - "CHILD": function( type, argument, first, last ) { - - if ( type === "nth" ) { - var doneName = done++; - - return function( elem ) { - var parent, diff, - count = 0, - node = elem; - - if ( first === 1 && last === 0 ) { - return true; - } - - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { - break; - } - } - } - - parent[ expando ] = doneName; - } - - diff = elem.sizset - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - }; - } - - return function( elem ) { - var node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - /* falls through */ - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - } - }; - }, - - "PSEUDO": function( pseudo, argument, context, xml ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( "unsupported pseudo: " + pseudo ); - } - - // The user may set fn.sizzleFilter to indicate - // that arguments are needed to create the filter function - // just as Sizzle does - if ( !fn.sizzleFilter ) { - return fn; - } - - return fn( argument, context, xml ); - } - }, - - pseudos: { - "not": markFunction(function( selector, context, xml ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); - return function( elem ) { - return !matcher( elem ); - }; - }), - - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - var nodeType; - elem = elem.firstChild; - while ( elem ) { - if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { - return false; - } - elem = elem.nextSibling; - } - return true; - }, - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "text": function( elem ) { - var type, attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - (type = elem.type) === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); - }, - - // Input types - "radio": createInputFunction("radio"), - "checkbox": createInputFunction("checkbox"), - "file": createInputFunction("file"), - "password": createInputFunction("password"), - "image": createInputFunction("image"), - - "submit": createButtonFunction("submit"), - "reset": createButtonFunction("reset"), - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "focus": function( elem ) { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); - }, - - "active": function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - - setFilters: { - "first": function( elements, argument, not ) { - return not ? elements.slice( 1 ) : [ elements[0] ]; - }, - - "last": function( elements, argument, not ) { - var elem = elements.pop(); - return not ? elements : [ elem ]; - }, - - "even": function( elements, argument, not ) { - var results = [], - i = not ? 1 : 0, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "odd": function( elements, argument, not ) { - var results = [], - i = not ? 0 : 1, - len = elements.length; - for ( ; i < len; i = i + 2 ) { - results.push( elements[i] ); - } - return results; - }, - - "lt": function( elements, argument, not ) { - return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); - }, - - "gt": function( elements, argument, not ) { - return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); - }, - - "eq": function( elements, argument, not ) { - var elem = elements.splice( +argument, 1 ); - return not ? elements : elem; - } - } -}; - -// Deprecated -Expr.setFilters["nth"] = Expr.setFilters["eq"]; - -// Back-compat -Expr.filters = Expr.pseudos; - -// IE6/7 return a modified href -if ( !assertHrefNotNormalized ) { - Expr.attrHandle = { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; -} - -// Add getElementsByName if usable -if ( assertUsableName ) { - Expr.order.push("NAME"); - Expr.find["NAME"] = function( name, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; -} - -// Add getElementsByClassName if usable -if ( assertUsableClassName ) { - Expr.order.splice( 1, 0, "CLASS" ); - Expr.find["CLASS"] = function( className, context, xml ) { - if ( typeof context.getElementsByClassName !== strundefined && !xml ) { - return context.getElementsByClassName( className ); - } - }; -} - -// If slice is not available, provide a backup -try { - slice.call( docElem.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, results = []; - for ( ; (elem = this[i]); i++ ) { - results.push( elem ); - } - return results; - }; -} - -var isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Element contains another -var contains = Sizzle.contains = docElem.compareDocumentPosition ? - function( a, b ) { - return !!( a.compareDocumentPosition( b ) & 16 ); - } : - docElem.contains ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); - } : - function( a, b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - return false; - }; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -var getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( nodeType ) { - if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - } else { - - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } - return ret; -}; - -Sizzle.attr = function( elem, name ) { - var attr, - xml = isXML( elem ); - - if ( !xml ) { - name = name.toLowerCase(); - } - if ( Expr.attrHandle[ name ] ) { - return Expr.attrHandle[ name ]( elem ); - } - if ( assertAttributes || xml ) { - return elem.getAttribute( name ); - } - attr = elem.getAttributeNode( name ); - return attr ? - typeof elem[ name ] === "boolean" ? - elem[ name ] ? name : null : - attr.specified ? attr.value : null : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - return (baseHasDuplicate = 0); -}); - - -if ( docElem.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? - a.compareDocumentPosition : - a.compareDocumentPosition(b) & 4 - ) ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - i = 1; - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -function multipleContexts( selector, contexts, results, seed ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results, seed ); - } -} - -function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { - var results, - fn = Expr.setFilters[ posfilter.toLowerCase() ]; - - if ( !fn ) { - Sizzle.error( posfilter ); - } - - if ( selector || !(results = seed) ) { - multipleContexts( selector || "*", contexts, (results = []), seed ); - } - - return results.length > 0 ? fn( results, argument, not ) : []; -} - -function handlePOS( selector, context, results, seed, groups ) { - var match, not, anchor, ret, elements, currentContexts, part, lastIndex, - i = 0, - len = groups.length, - rpos = matchExpr["POS"], - // This is generated here in case matchExpr["POS"] is extended - rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), - // This is for making sure non-participating - // matching groups are represented cross-browser (IE6-8) - setUndefined = function() { - var i = 1, - len = arguments.length - 2; - for ( ; i < len; i++ ) { - if ( arguments[i] === undefined ) { - match[i] = undefined; - } - } - }; - - for ( ; i < len; i++ ) { - // Reset regex index to 0 - rpos.exec(""); - selector = groups[i]; - ret = []; - anchor = 0; - elements = seed; - while ( (match = rpos.exec( selector )) ) { - lastIndex = rpos.lastIndex = match.index + match[0].length; - if ( lastIndex > anchor ) { - part = selector.slice( anchor, match.index ); - anchor = lastIndex; - currentContexts = [ context ]; - - if ( rcombinators.test(part) ) { - if ( elements ) { - currentContexts = elements; - } - elements = seed; - } - - if ( (not = rendsWithNot.test( part )) ) { - part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); - } - - if ( match.length > 1 ) { - match[0].replace( rposgroups, setUndefined ); - } - elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); - } - } - - if ( elements ) { - ret = ret.concat( elements ); - - if ( (part = selector.slice( anchor )) && part !== ")" ) { - if ( rcombinators.test(part) ) { - multipleContexts( part, ret, results, seed ); - } else { - Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); - } - } else { - push.apply( results, ret ); - } - } else { - Sizzle( selector, context, results, seed ); - } - } - - // Do not sort if this is a single filter - return len === 1 ? results : Sizzle.uniqueSort( results ); -} - -function tokenize( selector, context, xml ) { - var tokens, soFar, type, - groups = [], - i = 0, - - // Catch obvious selector issues: terminal ")"; nonempty fallback match - // rselector never fails to match *something* - match = rselector.exec( selector ), - matched = !match.pop() && !match.pop(), - selectorGroups = matched && selector.match( rgroups ) || [""], - - preFilters = Expr.preFilter, - filters = Expr.filter, - checkContext = !xml && context !== document; - - for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { - groups.push( tokens = [] ); - - // Need to make sure we're within a narrower context if necessary - // Adding a descendant combinator will generate what is needed - if ( checkContext ) { - soFar = " " + soFar; - } - - while ( soFar ) { - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - soFar = soFar.slice( match[0].length ); - - // Cast descendant combinators to space - matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); - } - - // Filters - for ( type in filters ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match, context, xml )) ) ) { - - soFar = soFar.slice( match.shift().length ); - matched = tokens.push({ part: type, captures: match }); - } - } - - if ( !matched ) { - break; - } - } - } - - if ( !matched ) { - Sizzle.error( selector ); - } - - return groups; -} - -function addCombinator( matcher, combinator, context ) { - var dir = combinator.dir, - doneName = done++; - - if ( !matcher ) { - // If there is no matcher to check, check against the context - matcher = function( elem ) { - return elem === context; - }; - } - return combinator.first ? - function( elem, context ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - return matcher( elem, context ) && elem; - } - } - } : - function( elem, context ) { - var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 ) { - if ( (cache = elem[ expando ]) === cachedkey ) { - return elem.sizset; - } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { - if ( elem.sizset ) { - return elem; - } - } else { - elem[ expando ] = cachedkey; - if ( matcher( elem, context ) ) { - elem.sizset = true; - return elem; - } - elem.sizset = false; - } - } - } - }; -} - -function addMatcher( higher, deeper ) { - return higher ? - function( elem, context ) { - var result = deeper( elem, context ); - return result && higher( result === true ? elem : result, context ); - } : - deeper; -} - -// ["TAG", ">", "ID", " ", "CLASS"] -function matcherFromTokens( tokens, context, xml ) { - var token, matcher, - i = 0; - - for ( ; (token = tokens[i]); i++ ) { - if ( Expr.relative[ token.part ] ) { - matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); - } else { - token.captures.push( context, xml ); - matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); - } - } - - return matcher; -} - -function matcherFromGroupMatchers( matchers ) { - return function( elem, context ) { - var matcher, - j = 0; - for ( ; (matcher = matchers[j]); j++ ) { - if ( matcher(elem, context) ) { - return true; - } - } - return false; - }; -} - -var compile = Sizzle.compile = function( selector, context, xml ) { - var tokens, group, i, - cached = compilerCache[ selector ]; - - // Return a cached group function if already generated (context dependent) - if ( cached && cached.context === context ) { - return cached; - } - - // Generate a function of recursive functions that can be used to check each element - group = tokenize( selector, context, xml ); - for ( i = 0; (tokens = group[i]); i++ ) { - group[i] = matcherFromTokens( tokens, context, xml ); - } - - // Cache the compiled function - cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); - cached.context = context; - cached.runs = cached.dirruns = 0; - cachedSelectors.push( selector ); - // Ensure only the most recent are cached - if ( cachedSelectors.length > Expr.cacheLength ) { - delete compilerCache[ cachedSelectors.shift() ]; - } - return cached; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - return Sizzle( expr, null, null, [ elem ] ).length > 0; -}; - -var select = function( selector, context, results, seed, xml ) { - // Remove excessive whitespace - selector = selector.replace( rtrim, "$1" ); - var elements, matcher, i, len, elem, token, - type, findContext, notTokens, - match = selector.match( rgroups ), - tokens = selector.match( rtokens ), - contextNodeType = context.nodeType; - - // POS handling - if ( matchExpr["POS"].test(selector) ) { - return handlePOS( selector, context, results, seed, match ); - } - - if ( seed ) { - elements = slice.call( seed, 0 ); - - // To maintain document order, only narrow the - // set if there is one group - } else if ( match && match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - if ( tokens.length > 1 && contextNodeType === 9 && !xml && - (match = matchExpr["ID"].exec( tokens[0] )) ) { - - context = Expr.find["ID"]( match[1], context, xml )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().length ); - } - - findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; - - // Get the last token, excluding :not - notTokens = tokens.pop(); - token = notTokens.split(":not")[0]; - - for ( i = 0, len = Expr.order.length; i < len; i++ ) { - type = Expr.order[i]; - - if ( (match = matchExpr[ type ].exec( token )) ) { - elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); - - if ( elements == null ) { - continue; - } - - if ( token === notTokens ) { - selector = selector.slice( 0, selector.length - notTokens.length ) + - token.replace( matchExpr[ type ], "" ); - - if ( !selector ) { - push.apply( results, slice.call(elements, 0) ); - } - } - break; - } - } - } - - // Only loop over the given elements once - // If selector is empty, we're already done - if ( selector ) { - matcher = compile( selector, context, xml ); - dirruns = matcher.dirruns++; - - if ( elements == null ) { - elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); - } - for ( i = 0; (elem = elements[i]); i++ ) { - cachedruns = matcher.runs++; - if ( matcher(elem, context) ) { - results.push( elem ); - } - } - } - - return results; -}; - -if ( document.querySelectorAll ) { - (function() { - var disconnectedMatch, - oldSelect = select, - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - rbuggyQSA = [], - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - // A support test would require too much code (would include document ready) - // just skip matchesSelector for :active - rbuggyMatches = [":active"], - matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here (do not put tests after this one) - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE9 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = "

        "; - if ( div.querySelectorAll("[test^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here (do not put tests after this one) - div.innerHTML = ""; - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push(":enabled", ":disabled"); - } - }); - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - - select = function( selector, context, results, seed, xml ) { - // Only use querySelectorAll when not filtering, - // when this is not xml, - // and when no QSA bugs apply - if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - if ( context.nodeType === 9 ) { - try { - push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); - return results; - } catch(qsaError) {} - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var old = context.getAttribute("id"), - nid = old || expando, - newContext = rsibling.test( selector ) && context.parentNode || context; - - if ( old ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - - try { - push.apply( results, slice.call( newContext.querySelectorAll( - selector.replace( rgroups, "[id='" + nid + "'] $&" ) - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - - return oldSelect( selector, context, results, seed, xml ); - }; - - if ( matches ) { - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - try { - matches.call( div, "[test!='']:sizzle" ); - rbuggyMatches.push( Expr.match.PSEUDO ); - } catch ( e ) {} - }); - - // rbuggyMatches always contains :active, so no need for a length check - rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); - - Sizzle.matchesSelector = function( elem, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyMatches always contains :active, so no need for an existence check - if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, null, null, [ elem ] ).length > 0; - }; - } - })(); -} - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, l, length, n, r, ret, - self = this; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - ret = this.pushStack( "", "find", selector ); - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /]", "i"), - rcheckableType = /^(?:checkbox|radio)$/, - // checked="checked" or checked - rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rscriptType = /\/(java|ecma)script/i, - rcleanScript = /^\s*\s*$/g, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, -// unless wrapped in a div with non-breaking characters in front of it. -if ( !jQuery.support.htmlSerialize ) { - wrapMap._default = [ 1, "X
        ", "
        " ]; -} - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); - } - }, - - after: function() { - if ( !isDisconnected( this[0] ) ) { - return this.domManip(arguments, false, function( elem ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - } - - if ( arguments.length ) { - var set = jQuery.clean( arguments ); - return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); - } - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - jQuery.cleanData( [ elem ] ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName("*") ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( elem.getElementsByTagName( "*" ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - if ( !isDisconnected( this[0] ) ) { - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this), old = self.html(); - self.replaceWith( value.call( this, i, old ) ); - }); - } - - if ( typeof value !== "string" ) { - value = jQuery( value ).detach(); - } - - return this.each(function() { - var next = this.nextSibling, - parent = this.parentNode; - - jQuery( this ).remove(); - - if ( next ) { - jQuery(next).before( value ); - } else { - jQuery(parent).append( value ); - } - }); - } - - return this.length ? - this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : - this; - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = [].concat.apply( [], args ); - - var results, first, fragment, iNoClone, - i = 0, - value = args[0], - scripts = [], - l = this.length; - - // We can't cloneNode fragments that contain checked, in WebKit - if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { - return this.each(function() { - jQuery(this).domManip( args, table, callback ); - }); - } - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - args[0] = value.call( this, i, table ? self.html() : undefined ); - self.domManip( args, table, callback ); - }); - } - - if ( this[0] ) { - results = jQuery.buildFragment( args, this, scripts ); - fragment = results.fragment; - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - // Fragments from the fragment cache must always be cloned and never used in place. - for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - i === iNoClone ? - fragment : - jQuery.clone( fragment, true, true ) - ); - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - - if ( scripts.length ) { - jQuery.each( scripts, function( i, elem ) { - if ( elem.src ) { - if ( jQuery.ajax ) { - jQuery.ajax({ - url: elem.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.error("no ajax"); - } - } else { - jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } - }); - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function cloneFixAttributes( src, dest ) { - var nodeName; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - // clearAttributes removes the attributes, which we don't want, - // but also removes the attachEvent events, which we *do* want - if ( dest.clearAttributes ) { - dest.clearAttributes(); - } - - // mergeAttributes, in contrast, only merges back on the - // original attributes, not the events - if ( dest.mergeAttributes ) { - dest.mergeAttributes( src ); - } - - nodeName = dest.nodeName.toLowerCase(); - - if ( nodeName === "object" ) { - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - - // IE blanks contents when cloning scripts - } else if ( nodeName === "script" && dest.text !== src.text ) { - dest.text = src.text; - } - - // Event data gets referenced instead of copied if the expando - // gets copied too - dest.removeAttribute( jQuery.expando ); -} - -jQuery.buildFragment = function( args, context, scripts ) { - var fragment, cacheable, cachehit, - first = args[ 0 ]; - - // Set context from what may come in as undefined or a jQuery collection or a node - context = context || document; - context = (context[0] || context).ownerDocument || context[0] || context; - - // Ensure that an attr object doesn't incorrectly stand in as a document object - // Chrome and Firefox seem to allow this to occur and will throw exception - // Fixes #8950 - if ( typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Only cache "small" (1/2 KB) HTML strings that are associated with the main document - // Cloning options loses the selected state, so don't cache them - // IE 6 doesn't like it when you put or elements in a fragment - // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 - if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && - first.charAt(0) === "<" && !rnocache.test( first ) && - (jQuery.support.checkClone || !rchecked.test( first )) && - (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { - - // Mark cacheable and look for a hit - cacheable = true; - fragment = jQuery.fragments[ first ]; - cachehit = fragment !== undefined; - } - - if ( !fragment ) { - fragment = context.createDocumentFragment(); - jQuery.clean( args, context, fragment, scripts ); - - // Update the cache, but only store false - // unless this is a second parsing of the same content - if ( cacheable ) { - jQuery.fragments[ first ] = cachehit && fragment; - } - } - - return { fragment: fragment, cacheable: cacheable }; -}; - -jQuery.fragments = {}; - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - l = insert.length, - parent = this.length === 1 && this[0].parentNode; - - if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { - insert[ original ]( this[0] ); - return this; - } else { - for ( ; i < l; i++ ) { - elems = ( i > 0 ? this.clone(true) : this ).get(); - jQuery( insert[i] )[ original ]( elems ); - ret = ret.concat( elems ); - } - - return this.pushStack( ret, name, insert.selector ); - } - }; -}); - -function getAll( elem ) { - if ( typeof elem.getElementsByTagName !== "undefined" ) { - return elem.getElementsByTagName( "*" ); - - } else if ( typeof elem.querySelectorAll !== "undefined" ) { - return elem.querySelectorAll( "*" ); - - } else { - return []; - } -} - -// Used in clean, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var srcElements, - destElements, - i, - clone; - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - // IE copies events bound via attachEvent when using cloneNode. - // Calling detachEvent on the clone will also remove the events - // from the original. In order to get around this, we use some - // proprietary methods to clear the events. Thanks to MooTools - // guys for this hotness. - - cloneFixAttributes( elem, clone ); - - // Using Sizzle here is crazy slow, so we use getElementsByTagName instead - srcElements = getAll( elem ); - destElements = getAll( clone ); - - // Weird iteration because IE will replace the length property - // with an element if you are cloning the body and one of the - // elements on the page has a name or id of "length" - for ( i = 0; srcElements[i]; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - cloneFixAttributes( srcElements[i], destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - cloneCopyEvent( elem, clone ); - - if ( deepDataAndEvents ) { - srcElements = getAll( elem ); - destElements = getAll( clone ); - - for ( i = 0; srcElements[i]; ++i ) { - cloneCopyEvent( srcElements[i], destElements[i] ); - } - } - } - - srcElements = destElements = null; - - // Return the cloned set - return clone; - }, - - clean: function( elems, context, fragment, scripts ) { - var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, - i = 0, - ret = []; - - // Ensure that context is a document - if ( !context || typeof context.createDocumentFragment === "undefined" ) { - context = document; - } - - // Use the already-created safe fragment if context permits - for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { - if ( typeof elem === "number" ) { - elem += ""; - } - - if ( !elem ) { - continue; - } - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - if ( !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); - } else { - // Ensure a safe container in which to render the html - safe = safe || createSafeFragment( context ); - div = div || safe.appendChild( context.createElement("div") ); - - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); - - // Go to html and back, then peel off extra wrappers - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - depth = wrap[0]; - div.innerHTML = wrap[1] + elem + wrap[2]; - - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - hasBody = rtbody.test(elem); - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : - - // String was a bare or - wrap[1] === "
        " && !hasBody ? - div.childNodes : - []; - - for ( j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); - } - } - } - - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); - } - - elem = div.childNodes; - - // Remember the top-level container for proper cleanup - div = safe.lastChild; - } - } - - if ( elem.nodeType ) { - ret.push( elem ); - } else { - ret = jQuery.merge( ret, elem ); - } - } - - // Fix #11356: Clear elements from safeFragment - if ( div ) { - safe.removeChild( div ); - elem = div = safe = null; - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - for ( i = 0; (elem = ret[i]) != null; i++ ) { - if ( jQuery.nodeName( elem, "input" ) ) { - fixDefaultChecked( elem ); - } else if ( typeof elem.getElementsByTagName !== "undefined" ) { - jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); - } - } - } - - // Append elements to a provided document fragment - if ( fragment ) { - // Special handling of each script element - handleScript = function( elem ) { - // Check if we consider it executable - if ( !elem.type || rscriptType.test( elem.type ) ) { - // Detach the script and store it in the scripts array (if provided) or the fragment - // Return truthy to indicate that it has been handled - return scripts ? - scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : - fragment.appendChild( elem ); - } - }; - - for ( i = 0; (elem = ret[i]) != null; i++ ) { - // Check if we're done after handling an executable script - if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { - // Append to fragment and handle embedded scripts - fragment.appendChild( elem ); - if ( typeof elem.getElementsByTagName !== "undefined" ) { - // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration - jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); - - // Splice the scripts into ret after their former ancestor and advance our index beyond them - ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); - i += jsTags.length; - } - } - } - } - - return ret; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var data, id, elem, type, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - jQuery.deletedIds.push( id ); - } - } - } - } - } -}); -// Limit scope pollution from any deprecated API -(function() { - -var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat -jQuery.uaMatch = function( ua ) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || - /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; -}; - -matched = jQuery.uaMatch( navigator.userAgent ); -browser = {}; - -if ( matched.browser ) { - browser[ matched.browser ] = true; - browser.version = matched.version; -} - -// Deprecated, use jQuery.browser.webkit instead -// Maintained for back-compat only -if ( browser.webkit ) { - browser.safari = true; -} - -jQuery.browser = browser; - -jQuery.sub = function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; -}; - -})(); -var curCSS, iframe, iframeDoc, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity=([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), - elemdisplay = {}, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400, - lineHeight: 1 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], - - eventsToggle = jQuery.fn.toggle; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var elem, display, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - values[ index ] = jQuery._data( elem, "olddisplay" ); - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && elem.style.display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - display = curCSS( elem, "display" ); - - if ( !values[ index ] && display !== "none" ) { - jQuery._data( elem, "olddisplay", display ); - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state, fn2 ) { - var bool = typeof state === "boolean"; - - if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { - return eventsToggle.apply( this, arguments ); - } - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, numeric, extra ) { - var val, num, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( numeric || extra !== undefined ) { - num = parseFloat( val ); - return numeric || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: To any future maintainer, we've used both window.getComputedStyle -// and getComputedStyle here to produce a better gzip size -if ( window.getComputedStyle ) { - curCSS = function( elem, name ) { - var ret, width, minWidth, maxWidth, - computed = getComputedStyle( elem, null ), - style = elem.style; - - if ( computed ) { - - ret = computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - curCSS = function( elem, name ) { - var left, rsLeft, - ret = elem.currentStyle && elem.currentStyle[ name ], - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - elem.runtimeStyle.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - // we use jQuery.css instead of curCSS here - // because of the reliableMarginRight CSS hook! - val += jQuery.css( elem, extra + cssExpand[ i ], true ); - } - - // From this point on we use curCSS for maximum performance (relevant in animations) - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } else { - // at this point, extra isn't content, so add padding - val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - valueIsBorderBox = true, - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; - - if ( val <= 0 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox - ) - ) + "px"; -} - - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - if ( elemdisplay[ nodeName ] ) { - return elemdisplay[ nodeName ]; - } - - var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), - display = elem.css("display"); - elem.remove(); - - // If the simple way fails, - // get element's real default display by attaching it to a temp iframe - if ( display === "none" || display === "" ) { - // Use the already-created iframe if possible - iframe = document.body.appendChild( - iframe || jQuery.extend( document.createElement("iframe"), { - frameBorder: 0, - width: 0, - height: 0 - }) - ); - - // Create a cacheable copy of the iframe document on first call. - // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML - // document to it; WebKit & Firefox won't allow reusing the iframe document. - if ( !iframeDoc || !iframe.createElement ) { - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeDoc.write(""); - iframeDoc.close(); - } - - elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); - - display = curCSS( elem, "display" ); - document.body.removeChild( iframe ); - } - - // Store the correct default display - elemdisplay[ nodeName ] = display; - - return display; -} - -jQuery.each([ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { - return getWidthOrHeight( elem, name, extra ); - } else { - return jQuery.swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - }); - } - } - }, - - set: function( elem, value, extra ) { - return setPositiveNumber( elem, value, extra ? - augmentWidthOrHeight( - elem, - name, - extra, - jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" - ) : 0 - ); - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? - ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style, - currentStyle = elem.currentStyle, - opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", - filter = currentStyle && currentStyle.filter || style.filter || ""; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 - if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && - style.removeAttribute ) { - - // Setting style.filter to null, "" & " " still leave "filter:" in the cssText - // if "filter:" is present at all, clearType is disabled, we want to avoid this - // style.removeAttribute is IE Only, but so apparently is this code path... - style.removeAttribute( "filter" ); - - // if there there is no filter style applied in a css rule, we are done - if ( currentStyle && !currentStyle.filter ) { - return; - } - } - - // otherwise, set new filter values - style.filter = ralpha.test( filter ) ? - filter.replace( ralpha, opacity ) : - filter + " " + opacity; - } - }; -} - -// These hooks cannot be added until DOM ready because the support test -// for it is not run until after DOM ready -jQuery(function() { - if ( !jQuery.support.reliableMarginRight ) { - jQuery.cssHooks.marginRight = { - get: function( elem, computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block - return jQuery.swap( elem, { "display": "inline-block" }, function() { - if ( computed ) { - return curCSS( elem, "marginRight" ); - } - }); - } - }; - } - - // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 - // getComputedStyle returns percent when specified for top/left/bottom/right - // rather than make the css module depend on the offset module, we just check for it here - if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { - jQuery.each( [ "top", "left" ], function( i, prop ) { - jQuery.cssHooks[ prop ] = { - get: function( elem, computed ) { - if ( computed ) { - var ret = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset - return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; - } - } - }; - }); - } - -}); - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.hidden = function( elem ) { - return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); - }; - - jQuery.expr.filters.visible = function( elem ) { - return !jQuery.expr.filters.hidden( elem ); - }; -} - -// These hooks are used by animate to expand properties -jQuery.each({ - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i, - - // assumes a single number if not a string - parts = typeof value === "string" ? value.split(" ") : [ value ], - expanded = {}; - - for ( i = 0; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -}); -var r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, - rselectTextarea = /^(?:select|textarea)/i; - -jQuery.fn.extend({ - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); - -//Serialize an array of form elements or a set of -//key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); -}; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} -var // Document location - ajaxLocation, - // Document location segments - ajaxLocParts, - - rhash = /#.*$/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - rquery = /\?/, - rscript = /)<[^<]*)*<\/script>/gi, - rts = /([?&])_=[^&]*/, - rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, - - // Keep a copy of the old load method - _load = jQuery.fn.load, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = ["*/"] + ["*"]; - -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} - -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, list, placeBefore, - dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), - i = 0, - length = dataTypes.length; - - if ( jQuery.isFunction( func ) ) { - // For each dataType in the dataTypeExpression - for ( ; i < length; i++ ) { - dataType = dataTypes[ i ]; - // We control if we're asked to add before - // any existing element - placeBefore = /^\+/.test( dataType ); - if ( placeBefore ) { - dataType = dataType.substr( 1 ) || "*"; - } - list = structure[ dataType ] = structure[ dataType ] || []; - // then we add to the structure accordingly - list[ placeBefore ? "unshift" : "push" ]( func ); - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, - dataType /* internal */, inspected /* internal */ ) { - - dataType = dataType || options.dataTypes[ 0 ]; - inspected = inspected || {}; - - inspected[ dataType ] = true; - - var selection, - list = structure[ dataType ], - i = 0, - length = list ? list.length : 0, - executeOnly = ( structure === prefilters ); - - for ( ; i < length && ( executeOnly || !selection ); i++ ) { - selection = list[ i ]( options, originalOptions, jqXHR ); - // If we got redirected to another dataType - // we try there if executing only and not done already - if ( typeof selection === "string" ) { - if ( !executeOnly || inspected[ selection ] ) { - selection = undefined; - } else { - options.dataTypes.unshift( selection ); - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, selection, inspected ); - } - } - } - // If we're only executing or nothing was selected - // we try the catchall dataType if not done already - if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { - selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, jqXHR, "*", inspected ); - } - // unnecessary when only executing (prefilters) - // but it'll be ignored by the caller in that case - return selection; -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } -} - -jQuery.fn.load = function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } - - var selector, type, response, - self = this, - off = url.indexOf(" "); - - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } - - // If it's a function - if ( jQuery.isFunction( params ) ) { - - // We assume that it's the callback - callback = params; - params = undefined; - - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } - - // Request the remote document - jQuery.ajax({ - url: url, - - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } - } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? - - // Create a dummy div to hold the results - jQuery("
        ") - - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) - - // Locate the specified elements - .find( selector ) : - - // If not, just inject the full result - responseText ); - - }); - - return this; -}; - -// Attach a bunch of functions for handling common AJAX events -jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ - jQuery.fn[ o ] = function( f ){ - return this.on( o, f ); - }; -}); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - return jQuery.ajax({ - type: method, - url: url, - data: data, - success: callback, - dataType: type - }); - }; -}); - -jQuery.extend({ - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - if ( settings ) { - // Building a settings object - ajaxExtend( target, jQuery.ajaxSettings ); - } else { - // Extending ajaxSettings - settings = target; - target = jQuery.ajaxSettings; - } - ajaxExtend( target, settings ); - return target; - }, - - ajaxSettings: { - url: ajaxLocation, - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), - global: true, - type: "GET", - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - processData: true, - async: true, - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - xml: "application/xml, text/xml", - html: "text/html", - text: "text/plain", - json: "application/json, text/javascript", - "*": allTypes - }, - - contents: { - xml: /xml/, - html: /html/, - json: /json/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText" - }, - - // List of data converters - // 1) key format is "source_type destination_type" (a single space in-between) - // 2) the catchall symbol "*" can be used for source_type - converters: { - - // Convert anything to text - "* text": window.String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": jQuery.parseJSON, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - context: true, - url: true - } - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var // ifModified key - ifModifiedKey, - // Response headers - responseHeadersString, - responseHeaders, - // transport - transport, - // timeout handle - timeoutTimer, - // Cross-domain detection vars - parts, - // To know if global events are to be dispatched - fireGlobals, - // Loop variable - i, - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - // Callbacks context - callbackContext = s.context || s, - // Context for global events - // It's the callbackContext if one was provided in the options - // and if it's a DOM node or a jQuery collection - globalEventContext = callbackContext !== s && - ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? - jQuery( callbackContext ) : jQuery.event, - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - // Status-dependent callbacks - statusCode = s.statusCode || {}, - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - // The jqXHR state - state = 0, - // Default abort message - strAbort = "canceled", - // Fake xhr - jqXHR = { - - readyState: 0, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( !state ) { - var lname = name.toLowerCase(); - name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Raw string - getAllResponseHeaders: function() { - return state === 2 ? responseHeadersString : null; - }, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( state === 2 ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match === undefined ? null : match; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( !state ) { - s.mimeType = type; - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - statusText = statusText || strAbort; - if ( transport ) { - transport.abort( statusText ); - } - done( 0, statusText ); - return this; - } - }; - - // Callback for when everything is done - // It is defined here because jslint complains if it is declared - // at the end of the function (which would be more logical and readable) - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Called once - if ( state === 2 ) { - return; - } - - // State is "done" now - state = 2; - - // Clear timeout if it exists - if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // If successful, handle type chaining - if ( status >= 200 && status < 300 || status === 304 ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - - modified = jqXHR.getResponseHeader("Last-Modified"); - if ( modified ) { - jQuery.lastModified[ ifModifiedKey ] = modified; - } - modified = jqXHR.getResponseHeader("Etag"); - if ( modified ) { - jQuery.etag[ ifModifiedKey ] = modified; - } - } - - // If not modified - if ( status === 304 ) { - - statusText = "notmodified"; - isSuccess = true; - - // If we have data - } else { - - isSuccess = ajaxConvert( s, response ); - statusText = isSuccess.state; - success = isSuccess.data; - error = isSuccess.error; - isSuccess = !error; - } - } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts - error = statusText; - if ( !statusText || status ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = "" + ( nativeStatusText || statusText ); - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - // Attach deferreds - deferred.promise( jqXHR ); - jqXHR.success = jqXHR.done; - jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.add; - - // Status-dependent callbacks - jqXHR.statusCode = function( map ) { - if ( map ) { - var tmp; - if ( state < 2 ) { - for ( tmp in map ) { - statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; - } - } else { - tmp = map[ jqXHR.status ]; - jqXHR.always( tmp ); - } - } - return this; - }; - - // Remove hash character (#7531: and string promotion) - // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) - // We also use the url parameter if available - s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); - - // Extract dataTypes list - s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace ); - - // Determine if a cross-domain request is in order - if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) - ); - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( state === 2 ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - fireGlobals = s.global; - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // If data is available, append data to url - if ( s.data ) { - s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Get ifModifiedKey before adding the anti-cache parameter - ifModifiedKey = s.url; - - // Add anti-cache in url if needed - if ( s.cache === false ) { - - var ts = jQuery.now(), - // try replacing _= if it is there - ret = s.url.replace( rts, "$1_=" + ts ); - - // if nothing was replaced, add timestamp to the end - s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - ifModifiedKey = ifModifiedKey || s.url; - if ( jQuery.lastModified[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); - } - if ( jQuery.etag[ ifModifiedKey ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); - } - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { - // Abort if not done already and return - return jqXHR.abort(); - - } - - // aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - for ( i in { success: 1, error: 1, complete: 1 } ) { - jqXHR[ i ]( s[ i ] ); - } - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout( function(){ - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - state = 1; - transport.send( requestHeaders, done ); - } catch (e) { - // Propagate exception as error if not done - if ( state < 2 ) { - done( -1, e ); - // Simply rethrow otherwise - } else { - throw e; - } - } - } - - return jqXHR; - }, - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {} - -}); - -/* Handles responses to an ajax request: - * - sets all responseXXX fields accordingly - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes, - responseFields = s.responseFields; - - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; - } - } - - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -// Chain conversions given the request and the original response -function ajaxConvert( s, response ) { - - var conv, conv2, current, tmp, - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(), - prev = dataTypes[ 0 ], - converters = {}, - i = 0; - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - // Convert to each sequential dataType, tolerating list modification - for ( ; (current = dataTypes[++i]); ) { - - // There's only work to do if current dataType is non-auto - if ( current !== "*" ) { - - // Convert response if prev dataType is non-auto and differs from current - if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split(" "); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.splice( i--, 0, current ); - } - - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s["throws"] ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; - } - } - } - } - - // Update prev for next iteration - prev = current; - } - } - - return { state: "success", data: response }; -} -var oldCallbacks = [], - rquestion = /\?/, - rjsonp = /(=)\?(?=&|$)|\?\?/, - nonce = jQuery.now(); - -// Default jsonp settings -jQuery.ajaxSetup({ - jsonp: "callback", - jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); - this[ callback ] = true; - return callback; - } -}); - -// Detect, normalize options and install callbacks for jsonp requests -jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var callbackName, overwritten, responseContainer, - data = s.data, - url = s.url, - hasCallback = s.jsonp !== false, - replaceInUrl = hasCallback && rjsonp.test( url ), - replaceInData = hasCallback && !replaceInUrl && typeof data === "string" && - !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && - rjsonp.test( data ); - - // Handle iff the expected data type is "jsonp" or we have a parameter to set - if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) { - - // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? - s.jsonpCallback() : - s.jsonpCallback; - overwritten = window[ callbackName ]; - - // Insert callback into url or form data - if ( replaceInUrl ) { - s.url = url.replace( rjsonp, "$1" + callbackName ); - } else if ( replaceInData ) { - s.data = data.replace( rjsonp, "$1" + callbackName ); - } else if ( hasCallback ) { - s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; - } - - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( callbackName + " was not called" ); - } - return responseContainer[ 0 ]; - }; - - // force json dataType - s.dataTypes[ 0 ] = "json"; - - // Install callback - window[ callbackName ] = function() { - responseContainer = arguments; - }; - - // Clean-up function (fires after converters) - jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; - - // Save back as free - if ( s[ callbackName ] ) { - // make sure that re-using the options doesn't screw things around - s.jsonpCallback = originalSettings.jsonpCallback; - - // save the callback name for future use - oldCallbacks.push( callbackName ); - } - - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { - overwritten( responseContainer[ 0 ] ); - } - - responseContainer = overwritten = undefined; - }); - - // Delegate to script - return "script"; - } -}); -// Install script dataType -jQuery.ajaxSetup({ - accepts: { - script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /javascript|ecmascript/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -}); - -// Handle cache's special case and global -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - s.global = false; - } -}); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - - var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; - - return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - - script.async = "async"; - - if ( s.scriptCharset ) { - script.charset = s.scriptCharset; - } - - script.src = s.url; - - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE - script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); - } - - // Dereference the script - script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); - } - } - }; - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709 and #4378). - head.insertBefore( script, head.firstChild ); - }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); - } - } - }; - } -}); -var xhrCallbacks, - // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); - } - } : false, - xhrId = 0; - -// Functions to create xhrs -function createStandardXHR() { - try { - return new window.XMLHttpRequest(); - } catch( e ) {} -} - -function createActiveXHR() { - try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} -} - -// Create the request object -// (This is still attached to ajaxSettings for backward compatibility) -jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ - function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); - } : - // For all other browsers, use the standard XMLHttpRequest object - createStandardXHR; - -// Determine support properties -(function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) - }); -})( jQuery.ajaxSettings.xhr() ); - -// Create transport if the browser can provide an xhr -if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { - // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - - var callback; - - return { - send: function( headers, complete ) { - - // Get a new xhr - var handle, i, - xhr = s.xhr(); - - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); - } else { - xhr.open( s.type, s.url, s.async ); - } - - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Need an extra try/catch for cross domain requests in Firefox 3 - try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - } catch( _ ) {} - - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { - - var status, - statusText, - responseHeaders, - responses, - xml; - - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occurred - // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) - try { - - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once - callback = undefined; - - // Do not keep as active anymore - if ( handle ) { - xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; - } - } - - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { - xhr.abort(); - } - } else { - status = xhr.status; - responseHeaders = xhr.getAllResponseHeaders(); - responses = {}; - xml = xhr.responseXML; - - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { - responses.xml = xml; - } - - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) - try { - responses.text = xhr.responseText; - } catch( _ ) { - } - - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests - try { - statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText - statusText = ""; - } - - // Filter status for non standard behaviors - - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { - status = 204; - } - } - } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); - } - } - - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); - } - }; - - if ( !s.async ) { - // if we're in sync mode we fire the callback - callback(); - } else if ( xhr.readyState === 4 ) { - // (IE6 & IE7) if it's in cache and has been - // retrieved directly we need to fire the callback - setTimeout( callback, 0 ); - } else { - handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); - } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; - } - xhr.onreadystatechange = callback; - } - }, - - abort: function() { - if ( callback ) { - callback(0,1); - } - } - }; - } - }); -} -var fxNow, timerId, - rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [function( prop, value ) { - var end, unit, prevScale, - tween = this.createTween( prop, value ), - parts = rfxnum.exec( value ), - target = tween.cur(), - start = +target || 0, - scale = 1; - - if ( parts ) { - end = +parts[2]; - unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - - // We need to compute starting value - if ( unit !== "px" && start ) { - // Iteratively approximate from a nonzero starting point - // Prefer the current property, because this process will be trivial if it uses the same units - // Fallback to end or a simple constant - start = jQuery.css( tween.elem, prop, true ) || end || 1; - - do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below - prevScale = scale = scale || ".5"; - - // Adjust and apply - start = start / scale; - jQuery.style( tween.elem, prop, start + unit ); - - // Update scale, tolerating zeroes from tween.cur() - scale = tween.cur() / target; - - // Stop looping if we've hit the mark or scale is unchanged - } while ( scale !== 1 && scale !== prevScale ); - } - - tween.unit = unit; - tween.start = start; - // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; - } - return tween; - }] - }; - -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout(function() { - fxNow = undefined; - }, 0 ); - return ( fxNow = jQuery.now() ); -} - -function createTweens( animation, props ) { - jQuery.each( props, function( prop, value ) { - var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( collection[ index ].call( animation, prop, value ) ) { - - // we're done with this property - return; - } - } - }); -} - -function Animation( elem, properties, options ) { - var result, - index = 0, - tweenerIndex = 0, - length = animationPrefilters.length, - deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector - delete tick.elem; - }), - tick = function() { - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - percent = 1 - ( remaining / animation.duration || 0 ), - index = 0, - length = animation.tweens.length; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ]); - - if ( percent < 1 && length ) { - return remaining; - } else { - deferred.resolveWith( elem, [ animation ] ); - return false; - } - }, - animation = deferred.promise({ - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { specialEasing: {} }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end, easing ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - // if we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - - for ( ; index < length ; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // resolve when we played the last frame - // otherwise, reject - if ( gotoEnd ) { - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - }), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - return result; - } - } - - createTweens( animation, props ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - jQuery.fx.timer( - jQuery.extend( tick, { - anim: animation, - queue: animation.opts.queue, - elem: elem - }) - ); - - // attach callbacks from options - return animation.progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( jQuery.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.split(" "); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length ; index++ ) { - prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); - } - }, - - prefilter: function( callback, prepend ) { - if ( prepend ) { - animationPrefilters.unshift( callback ); - } else { - animationPrefilters.push( callback ); - } - } -}); - -function defaultPrefilter( elem, props, opts ) { - var index, prop, value, length, dataShow, tween, hooks, oldfire, - anim = this, - style = elem.style, - orig = {}, - handled = [], - hidden = elem.nodeType && isHidden( elem ); - - // handle queue: false promises - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes - anim.always(function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - }); - }); - } - - // height/width overflow pass - if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { - // Make sure that nothing sneaks out - // Record all 3 overflow attributes because IE does not - // change the overflow attribute when overflowX and - // overflowY are set to the same value - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Set display property to inline-block for height/width - // animations on inline elements that are having width/height animated - if ( jQuery.css( elem, "display" ) === "inline" && - jQuery.css( elem, "float" ) === "none" ) { - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { - style.display = "inline-block"; - - } else { - style.zoom = 1; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - if ( !jQuery.support.shrinkWrapBlocks ) { - anim.done(function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - }); - } - } - - - // show/hide pass - for ( index in props ) { - value = props[ index ]; - if ( rfxtypes.exec( value ) ) { - delete props[ index ]; - if ( value === ( hidden ? "hide" : "show" ) ) { - continue; - } - handled.push( index ); - } - } - - length = handled.length; - if ( length ) { - dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); - if ( hidden ) { - jQuery( elem ).show(); - } else { - anim.done(function() { - jQuery( elem ).hide(); - }); - } - anim.done(function() { - var prop; - jQuery.removeData( elem, "fxshow", true ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - }); - for ( index = 0 ; index < length ; index++ ) { - prop = handled[ index ]; - tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); - orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); - - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = tween.start; - if ( hidden ) { - tween.end = tween.start; - tween.start = prop === "width" || prop === "height" ? 1 : 0; - } - } - } - } -} - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || "swing"; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { - return tween.elem[ tween.prop ]; - } - - // passing any value as a 4th parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. - result = jQuery.css( tween.elem, tween.prop, false, "" ); - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Remove in 2.0 - this supports IE8's panic based approach -// to setting things on disconnected nodes - -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" || - // special check for .toggle( handler, handler, ... ) - ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -}); - -jQuery.fn.extend({ - fadeTo: function( speed, to, easing, callback ) { - - // show any hidden elements after setting opacity to 0 - return this.filter( isHidden ).css( "opacity", 0 ).show() - - // animate to the value specified - .end().animate({ opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations resolve immediately - if ( empty ) { - anim.stop( true ); - } - }; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each(function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = jQuery._data( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - }); - } -}); - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - attrs = { height: type }, - i = 0; - - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right - for( ; i < 4 ; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -// Generate shortcuts for custom animations -jQuery.each({ - slideDown: genFx("show"), - slideUp: genFx("hide"), - slideToggle: genFx("toggle"), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -}); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - - // normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p*Math.PI ) / 2; - } -}; - -jQuery.timers = []; -jQuery.fx = Tween.prototype.init; -jQuery.fx.tick = function() { - var timer, - timers = jQuery.timers, - i = 0; - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - // Checks the timer has not already been removed - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } -}; - -jQuery.fx.timer = function( timer ) { - if ( timer() && jQuery.timers.push( timer ) && !timerId ) { - timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); - } -}; - -jQuery.fx.interval = 13; - -jQuery.fx.stop = function() { - clearInterval( timerId ); - timerId = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - // Default speed - _default: 400 -}; - -// Back Compat <1.8 extension point -jQuery.fx.step = {}; - -if ( jQuery.expr && jQuery.expr.filters ) { - jQuery.expr.filters.animated = function( elem ) { - return jQuery.grep(jQuery.timers, function( fn ) { - return elem === fn.elem; - }).length; - }; -} -var rroot = /^(?:body|html)$/i; - -jQuery.fn.offset = function( options ) { - if ( arguments.length ) { - return options === undefined ? - this : - this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left, - elem = this[ 0 ], - doc = elem && elem.ownerDocument; - - if ( !doc ) { - return; - } - - if ( (body = doc.body) === elem ) { - return jQuery.offset.bodyOffset( elem ); - } - - docElem = doc.documentElement; - - // Make sure we're not dealing with a disconnected DOM node - if ( !jQuery.contains( docElem, elem ) ) { - return { top: 0, left: 0 }; - } - - box = elem.getBoundingClientRect(); - win = getWindow( doc ); - clientTop = docElem.clientTop || body.clientTop || 0; - clientLeft = docElem.clientLeft || body.clientLeft || 0; - scrollTop = win.pageYOffset || docElem.scrollTop; - scrollLeft = win.pageXOffset || docElem.scrollLeft; - top = box.top + scrollTop - clientTop; - left = box.left + scrollLeft - clientLeft; - - return { top: top, left: left }; -}; - -jQuery.offset = { - - bodyOffset: function( body ) { - var top = body.offsetTop, - left = body.offsetLeft; - - if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { - top += parseFloat( jQuery.css(body, "marginTop") ) || 0; - left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; - } - - return { top: top, left: left }; - }, - - setOffset: function( elem, options, i ) { - var position = jQuery.css( elem, "position" ); - - // set position first, in-case top/left are set even on static elem - if ( position === "static" ) { - elem.style.position = "relative"; - } - - var curElem = jQuery( elem ), - curOffset = curElem.offset(), - curCSSTop = jQuery.css( elem, "top" ), - curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, - props = {}, curPosition = {}, curTop, curLeft; - - // need to be able to calculate position if either top or left is auto and position is either absolute or fixed - if ( calculatePosition ) { - curPosition = curElem.position(); - curTop = curPosition.top; - curLeft = curPosition.left; - } else { - curTop = parseFloat( curCSSTop ) || 0; - curLeft = parseFloat( curCSSLeft ) || 0; - } - - if ( jQuery.isFunction( options ) ) { - options = options.call( elem, i, curOffset ); - } - - if ( options.top != null ) { - props.top = ( options.top - curOffset.top ) + curTop; - } - if ( options.left != null ) { - props.left = ( options.left - curOffset.left ) + curLeft; - } - - if ( "using" in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - } -}; - - -jQuery.fn.extend({ - - position: function() { - if ( !this[0] ) { - return; - } - - var elem = this[0], - - // Get *real* offsetParent - offsetParent = this.offsetParent(), - - // Get correct offsets - offset = this.offset(), - parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; - offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; - - // Add offsetParent borders - parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; - parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - }; - }, - - offsetParent: function() { - return this.map(function() { - var offsetParent = this.offsetParent || document.body; - while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { - offsetParent = offsetParent.offsetParent; - } - return offsetParent || document.body; - }); - } -}); - - -// Create scrollLeft and scrollTop methods -jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { - var top = /Y/.test( prop ); - - jQuery.fn[ method ] = function( val ) { - return jQuery.access( this, function( elem, method, val ) { - var win = getWindow( elem ); - - if ( val === undefined ) { - return win ? (prop in win) ? win[ prop ] : - win.document.documentElement[ method ] : - elem[ method ]; - } - - if ( win ) { - win.scrollTo( - !top ? val : jQuery( win ).scrollLeft(), - top ? val : jQuery( win ).scrollTop() - ); - - } else { - elem[ method ] = val; - } - }, method, val, arguments.length, null ); - }; -}); - -function getWindow( elem ) { - return jQuery.isWindow( elem ) ? - elem : - elem.nodeType === 9 ? - elem.defaultView || elem.parentWindow : - false; -} -// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods -jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth - jQuery.fn[ funcName ] = function( margin, value ) { - var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), - extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); - - return jQuery.access( this, function( elem, type, value ) { - var doc; - - if ( jQuery.isWindow( elem ) ) { - // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there - // isn't a whole lot we can do. See pull request at this URL for discussion: - // https://github.com/jquery/jquery/pull/764 - return elem.document.documentElement[ "client" + name ]; - } - - // Get document width or height - if ( elem.nodeType === 9 ) { - doc = elem.documentElement; - - // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest - // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. - return Math.max( - elem.body[ "scroll" + name ], doc[ "scroll" + name ], - elem.body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - } - - return value === undefined ? - // Get width or height on the element, requesting but not forcing parseFloat - jQuery.css( elem, type, value, extra ) : - - // Set width or height on the element - jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); - }; - }); -}); -// Expose jQuery to the global object -window.jQuery = window.$ = jQuery; - -// Expose jQuery as an AMD module, but only for AMD loaders that -// understand the issues with loading multiple versions of jQuery -// in a page that all might call define(). The loader will indicate -// they have special allowances for multiple jQuery versions by -// specifying define.amd.jQuery = true. Register as a named module, -// since jQuery can be concatenated with other files that may use define, -// but not use a proper concatenation script that understands anonymous -// AMD modules. A named AMD is safest and most robust way to register. -// Lowercase jquery is used because AMD module names are derived from -// file names, and jQuery is normally delivered in a lowercase file name. -// Do this after creating the global so that if an AMD module wants to call -// noConflict to hide this version of jQuery, it will work. -if ( typeof define === "function" && define.amd && define.amd.jQuery ) { - define( "jquery", [], function () { return jQuery; } ); -} - -})( window );;/*! jQuery UI - v1.10.3 - 2013-06-12 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
        - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( "
        ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); -;/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011 - * http://benalman.com/ - * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */ - -(function($) { - - var o = $({}); - - $.subscribe = function() { - //console.log("SUBSCRIBE: " + arguments[0]); - o.on.apply(o, arguments); - }; - - $.unsubscribe = function() { - o.off.apply(o, arguments); - }; - - $.publish = function() { - //console.log("PUBLISH: " + arguments[0]); - o.trigger.apply(o, arguments); - }; - -}(jQuery)); - - -;/* =========================================================== - * bootstrap-tooltip.js v2.1.1 - * http://twitter.github.com/bootstrap/javascript.html#tooltips - * Inspired by the original jQuery.tipsy by Jason Frame - * =========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - - /* TOOLTIP PUBLIC CLASS DEFINITION - * =============================== */ - - var Tooltip = function (element, options) { - this.init('tooltip', element, options) - } - - Tooltip.prototype = { - - constructor: Tooltip - - , init: function (type, element, options) { - var eventIn - , eventOut - - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - this.enabled = true - - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) - } - - this.options.selector ? - (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : - this.fixTitle() - } - - , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) - - if (options.delay && typeof options.delay == 'number') { - options.delay = { - show: options.delay - , hide: options.delay - } - } - - return options - } - - , enter: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (!self.options.delay || !self.options.delay.show) return self.show() - - clearTimeout(this.timeout) - self.hoverState = 'in' - this.timeout = setTimeout(function() { - if (self.hoverState == 'in') self.show() - }, self.options.delay.show) - } - - , leave: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - - if (this.timeout) clearTimeout(this.timeout) - if (!self.options.delay || !self.options.delay.hide) return self.hide() - - self.hoverState = 'out' - this.timeout = setTimeout(function() { - if (self.hoverState == 'out') self.hide() - }, self.options.delay.hide) - } - - , show: function () { - var $tip - , inside - , pos - , actualWidth - , actualHeight - , placement - , tp - - if (this.hasContent() && this.enabled) { - $tip = this.tip() - this.setContent() - - if (this.options.animation) { - $tip.addClass('fade') - } - - placement = typeof this.options.placement == 'function' ? - this.options.placement.call(this, $tip[0], this.$element[0]) : - this.options.placement - - inside = /in/.test(placement) - - $tip - .remove() - .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) - - pos = this.getPosition(inside) - - actualWidth = $tip[0].offsetWidth - actualHeight = $tip[0].offsetHeight - - switch (inside ? placement.split(' ')[1] : placement) { - case 'bottom': - tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'top': - tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} - break - case 'left': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} - break - case 'right': - tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} - break - } - - $tip - .css(tp) - .addClass(placement) - .addClass('in') - } - } - - , setContent: function () { - var $tip = this.tip() - , title = this.getTitle() - - $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') - } - - , hide: function () { - var that = this - , $tip = this.tip() - - $tip.removeClass('in') - - function removeWithAnimation() { - var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() - }, 500) - - $tip.one($.support.transition.end, function () { - clearTimeout(timeout) - $tip.remove() - }) - } - - $.support.transition && this.$tip.hasClass('fade') ? - removeWithAnimation() : - $tip.remove() - - return this - } - - , fixTitle: function () { - var $e = this.$element - if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') - } - } - - , hasContent: function () { - return this.getTitle() - } - - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) - } - - , getTitle: function () { - var title - , $e = this.$element - , o = this.options - - title = $e.attr('data-original-title') - || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) - - return title - } - - , tip: function () { - return this.$tip = this.$tip || $(this.options.template) - } - - , validate: function () { - if (!this.$element[0].parentNode) { - this.hide() - this.$element = null - this.options = null - } - } - - , enable: function () { - this.enabled = true - } - - , disable: function () { - this.enabled = false - } - - , toggleEnabled: function () { - this.enabled = !this.enabled - } - - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() - } - - , destroy: function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - - } - - - /* TOOLTIP PLUGIN DEFINITION - * ========================= */ - - $.fn.tooltip = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('tooltip') - , options = typeof option == 'object' && option - if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.tooltip.Constructor = Tooltip - - $.fn.tooltip.defaults = { - animation: true - , placement: 'top' - , selector: false - , template: '
        ' - , trigger: 'hover' - , title: '' - , delay: 0 - , html: true - } - -}(window.jQuery); -;// TODO(grosbouddha): put under pskl namespace. -var Constants = { - DEFAULT : { - HEIGHT : 32, - WIDTH : 32, - FPS : 12 - }, - - MODEL_VERSION : 2, - - MAX_HEIGHT : 1024, - MAX_WIDTH : 1024, - - MAX_CURRENT_COLORS_DISPLAYED : 100, - - MINIMUM_ZOOM : 1, - - PREVIEW_FILM_SIZE : 96, - ANIMATED_PREVIEW_WIDTH : 200, - - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - - OVERLAY_ONION_SKIN : 'onion-skin', - OVERLAY_LAYER_PREVIEW : 'layer-preview', - OVERLAY_DISABLED : 'no-overlay', - - NO_PALETTE_ID : '__no-palette', - CURRENT_COLORS_PALETTE_ID : '__current-colors', - - // Used for Spectrum input - PREFERRED_COLOR_FORMAT : 'rgb', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - /* - * Default entry point for piskel web service: - */ - STATIC : { - URL : { - SAVE : 'http://3.piskel-app.appspot.com/store', - GET : 'http://3.piskel-app.appspot.com/get' - } - }, - APPENGINE : { - URL : { - SAVE : 'save' - } - }, - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-a.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-a.appspot.com/img/', - - ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', - - LEFT_BUTTON : 0, - MIDDLE_BUTTON : 1, - RIGHT_BUTTON : 2, - MOUSEMOVE_THROTTLING : 10, - - ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, - EMPTY_FUNCTION : function () {}, - - // TESTS - DRAWING_TEST_FOLDER : 'drawing' -};;// TODO(grosbouddha): put under pskl namespace. -var Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - SELECT_TOOL : "SELECT_TOOL", - - TOOL_RELEASED : "TOOL_RELEASED", - SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", - SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", - PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', - SECONDARY_COLOR_SELECTED : 'SECONDARY_COLOR_SELECTED', - - CURSOR_MOVED : 'CURSOR_MOVED', - DRAG_START : 'DRAG_START', - DRAG_END : 'DRAG_END', - - DIALOG_DISPLAY : 'DIALOG_DISPLAY', - DIALOG_HIDE : 'DIALOG_HIDE', - - PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED', - - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - PISKEL_RESET: "PISKEL_RESET", - PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE", - - PISKEL_SAVED: "PISKEL_SAVED", - - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - - ZOOM_CHANGED : "ZOOM_CHANGED", - - CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", - - MOUSE_EVENT : "MOUSE_EVENT", - - // Tests - TEST_RECORD_END : "TEST_RECORD_END", - TEST_CASE_END : "TEST_CASE_END", - TEST_SUITE_END : "TEST_SUITE_END" -};;jQuery.namespace = function() { - var a=arguments, o=null, i, j, d; - for (i=0; i 255 || g > 255 || b > 255) { - throw "Invalid color component"; - } - - return ((r << 16) | (g << 8) | b).toString(16); - }; - - ns.normalize = function (value, def) { - if (typeof value === 'undefined' || value === null) { - return def; - } else { - return value; - } - }; - - ns.inherit = function(extendedObject, inheritFrom) { - extendedObject.prototype = Object.create(inheritFrom.prototype); - extendedObject.prototype.constructor = extendedObject; - extendedObject.prototype.superclass = inheritFrom.prototype; - }; - - ns.wrap = function (wrapper, wrappedObject) { - for (var prop in wrappedObject) { - if (typeof wrappedObject[prop] === 'function' && typeof wrapper[prop] === 'undefined') { - wrapper[prop] = wrappedObject[prop].bind(wrappedObject); - } - } - }; - - var entityMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''', - "/": '/' - }; - - ns.escapeHtml= function (string) { - return String(string).replace(/[&<>"'\/]/g, function (s) { - return entityMap[s]; - }); - }; - - var reEntityMap = {}; - ns.unescapeHtml= function (string) { - Object.keys(entityMap).forEach(function(key) { - reEntityMap[key] = reEntityMap[key] || new RegExp(entityMap[key], "g"); - string = string.replace(reEntityMap[key], key); - }); - return string; - }; - -})(); - -;(function () { - var ns = $.namespace('pskl.utils'); - var ua = navigator.userAgent; - - ns.UserAgent = { - isIE : /MSIE/i.test( ua ), - isIE11 : /trident/i.test( ua ), - isChrome : /Chrome/i.test( ua ), - isFirefox : /Firefox/i.test( ua ), - isMac : /Mac/.test( ua ) - }; - - ns.UserAgent.version = (function () { - if (pskl.utils.UserAgent.isIE) { - return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isChrome) { - return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10); - } else if (pskl.utils.UserAgent.isFirefox) { - return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10); - } - })(); -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var base64_ranks; - if (Uint8Array) { - base64_ranks = new Uint8Array([ - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, - -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]); - } - - ns.Base64 = { - toText : function (base64) { - return window.atob(base64.replace(/data\:.*?\;base64\,/,'')); - }, - - decode : function(base64) { - var outptr = 0; - var last = [0, 0]; - var state = 0; - var save = 0; - - var undef; - var len = base64.length, i = 0; - var buffer = new Uint8Array(len / 4 * 3 | 0); - while (len--) { - var code = base64.charCodeAt(i++); - var rank = base64_ranks[code-43]; - if (rank !== 255 && rank !== undef) { - last[1] = last[0]; - last[0] = code; - save = (save << 6) | rank; - state++; - if (state === 4) { - buffer[outptr++] = save >>> 16; - if (last[1] !== 61 /* padding character */) { - buffer[outptr++] = save >>> 8; - } - if (last[0] !== 61 /* padding character */) { - buffer[outptr++] = save; - } - state = 0; - } - } - } - // 2/3 chance there's going to be some null bytes at the end, but that - // doesn't really matter with most image formats. - // If it somehow matters for you, truncate the buffer up outptr. - return buffer.buffer; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - - - var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; - - ns.BlobUtils = { - dataToBlob : function(dataURI, type, callback) { - var header_end = dataURI.indexOf(","), - data = dataURI.substring(header_end + 1), - isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)), - blob; - - if (Blob.fake) { - // no reason to decode a data: URI that's just going to become a data URI again - blob = new Blob(); - blob.encoding = isBase64 ? "base64" : "URI"; - blob.data = data; - blob.size = data.length; - } else if (Uint8Array) { - var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); - blob = new Blob([blobData], {type: type}); - } - callback(blob); - }, - - canvasToBlob : function(canvas, callback, type /*, ...args*/) { - type = type || "image/png"; - - if (canvas.mozGetAsFile) { - callback(canvas.mozGetAsFile("canvas", type)); - } else { - var args = Array.prototype.slice.call(arguments, 2); - var dataURI = canvas.toDataURL.apply(canvas, args); - pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback); - } - }, - - stringToBlob : function (string, callback, type) { - type = type || "text/plain"; - pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback); - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.CanvasUtils = { - createCanvas : function (width, height, classList) { - var canvas = document.createElement("canvas"); - canvas.setAttribute("width", width); - canvas.setAttribute("height", height); - - if (typeof classList == "string") { - classList = [classList]; - } - if (Array.isArray(classList)) { - for (var i = 0 ; i < classList.length ; i++) { - canvas.classList.add(classList[i]); - } - } - - return canvas; - }, - - createFromImageData : function (imageData) { - var canvas = pskl.CanvasUtils.createCanvas(imageData.width, imageData.height); - var context = canvas.getContext('2d'); - context.putImageData(imageData, 0, 0); - return canvas; - }, - - createFromImage : function (image) { - var canvas = pskl.CanvasUtils.createCanvas(image.width, image.height); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - return canvas; - }, - - /** - * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. - * Resizing a 32x32 image to 320x320 will lead to a blurry output. - * On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context. - * In this case the browser will use a nearest-neighbor scaling. - * @param {Canvas} canvas - */ - disableImageSmoothing : function (canvas) { - var context = canvas.getContext('2d'); - context.imageSmoothingEnabled = false; - context.mozImageSmoothingEnabled = false; - context.oImageSmoothingEnabled = false; - context.webkitImageSmoothingEnabled = false; - context.msImageSmoothingEnabled = false; - }, - - clear : function (canvas) { - if (canvas) { - canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); - } - }, - - clone : function (canvas) { - var clone = pskl.CanvasUtils.createCanvas(canvas.width, canvas.height); - - //apply the old canvas to the new one - clone.getContext('2d').drawImage(canvas, 0, 0); - - //return the new canvas - return clone; - }, - - getImageDataFromCanvas : function (canvas) { - var sourceContext = canvas.getContext('2d'); - return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; - }, - - getBase64FromCanvas : function (canvas, format) { - format = format || "png"; - var data = canvas.toDataURL("image/" + format); - return data.substr(data.indexOf(',')+1); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var pad = function (num) { - if (num < 10) { - return "0" + num; - } else { - return "" + num; - } - }; - - ns.DateUtils = { - format : function (date, format) { - date = new Date(date); - return pskl.utils.Template.replace(format, { - Y : date.getFullYear(), - M : pad(date.getMonth() + 1), - D : pad(date.getDate()), - H : pad(date.getHours()), - m : pad(date.getMinutes()), - s : pad(date.getSeconds()) - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Dom = { - /** - * Check if a given HTML element is nested inside another - * @param {HTMLElement} node Element to test - * @param {HTMLElement} parent Potential Ancestor for node - * @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches - * @return {Boolean} true if parent was found amongst the parentNode chain of node - */ - isParent : function (node, parent, excludeParent) { - if (node && parent) { - - if (excludeParent) { - node = node.parentNode; - } - - while (node) { - if (node === parent) { - return true; - } - node = node.parentNode; - } - } - return false; - }, - - getParentWithData : function (node, data) { - while (node) { - if (node.dataset && typeof node.dataset[data] !== 'undefined') { - return node; - } - node = node.parentNode; - } - return null; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Math = { - minmax : function (val, min, max) { - return Math.max(Math.min(val, max), min); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - var stopPropagation = function (e) { - e.stopPropagation(); - }; - - ns.FileUtils = { - readFile : function (file, callback) { - var reader = new FileReader(); - reader.onload = function(event){ - callback(event.target.result); - }; - reader.readAsDataURL(file); - }, - - readImageFile : function (file, callback) { - ns.FileUtils.readFile(file, function (content) { - var image = new Image(); - image.onload = callback.bind(null, image); - image.src = content; - }); - }, - - downloadAsFile : function (content, filename) { - var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); - if (saveAs) { - saveAs(content, filename); - } else { - var downloadLink = document.createElement('a'); - content = window.URL.createObjectURL(content); - downloadLink.setAttribute('href', content); - downloadLink.setAttribute('download', filename); - document.body.appendChild(downloadLink); - downloadLink.addEventListener('click', stopPropagation); - downloadLink.click(); - downloadLink.removeEventListener('click', stopPropagation); - document.body.removeChild(downloadLink); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - var colorCache = {}; - ns.FrameUtils = { - merge : function (frames) { - var merged = null; - if (frames.length) { - merged = frames[0].clone(); - var w = merged.getWidth(), h = merged.getHeight(); - for (var i = 1 ; i < frames.length ; i++) { - pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]); - } - } - return merged; - }, - - mergeFrames_ : function (frameA, frameB) { - frameB.forEachPixel(function (p, col, row) { - if (p != Constants.TRANSPARENT_COLOR) { - frameA.setPixel(col, row, p); - } - }); - }, - - resize : function (frame, targetWidth, targetHeight, smoothing) { - var image = pskl.utils.FrameUtils.toImage(frame); - var resizedImage = pskl.utils.ImageResizer.resize(image, targetWidth, targetHeight, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }, - - /** - * Alpha compositing using porter duff algorithm : - * http://en.wikipedia.org/wiki/Alpha_compositing - * http://keithp.com/~keithp/porterduff/p253-porter.pdf - * @param {String} strColor1 color over - * @param {String} strColor2 color under - * @return {String} the composite color - */ - mergePixels : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba(strColor2); - if (typeof globalOpacity1 == 'number') { - col1 = JSON.parse(JSON.stringify(col1)); - col1.a = globalOpacity1 * col1.a; - } - var a = col1.a + col2.a * (1 - col1.a); - - var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0; - var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0; - var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0; - - return 'rgba('+r+','+g+','+b+','+a+')'; - }, - - /** - * Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties. - * r, g and b are integers between 0 and 255, a is a float between 0 and 1 - * @param {String} c color as a string - * @return {Object} {r:Number,g:Number,b:Number,a:Number} - */ - toRgba : function (c) { - if (colorCache[c]) { - return colorCache[c]; - } - var color, matches; - if (c === 'TRANSPARENT') { - color = { - r : 0, - g : 0, - b : 0, - a : 0 - }; - } else if (c.indexOf('rgba(') != -1) { - matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : parseFloat(matches[4]) - }; - } else if (c.indexOf('rgb(') != -1) { - matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c); - color = { - r : parseInt(matches[1],10), - g : parseInt(matches[2],10), - b : parseInt(matches[3],10), - a : 1 - }; - } else { - matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c); - color = { - r : parseInt(matches[1], 16), - g : parseInt(matches[2], 16), - b : parseInt(matches[3], 16), - a : 1 - }; - } - colorCache[c] = color; - return color; - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData(imgData, w, h); - }, - - createFromImageData : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Convert a rgb(Number, Number, Number) color to hexadecimal representation - * @param {Number} r red value, between 0 and 255 - * @param {Number} g green value, between 0 and 255 - * @param {Number} b blue value, between 0 and 255 - * @return {String} hex representation of the color '#ABCDEF' - */ - rgbToHex : function (r, g, b) { - return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b); - }, - - /** - * Convert a color component (as a Number between 0 and 255) to its string hexa representation - * @param {Number} c component value, between 0 and 255 - * @return {String} eg. '0A' - */ - componentToHex : function (c) { - var hex = c.toString(16); - return hex.length == 1 ? "0" + hex : hex; - }, - - toImage : function (frame, zoom, bgColor) { - zoom = zoom || 1; - bgColor = bgColor || Constants.TRANSPARENT_COLOR; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(bgColor); - return canvasRenderer.render(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils'); - - ns.LayerUtils = { - /** - * Create a pskl.model.Layer from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image, frameCount) { - var w = image.width, - h = image.height, - frameWidth = w / frameCount; - - var canvas = pskl.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - // Draw the zoomed-up pixels to a different canvas context - var frames = []; - for (var i = 0 ; i < frameCount ; i++) { - var imgData = context.getImageData(frameWidth*i,0,frameWidth,h).data; - var frame = pskl.utils.FrameUtils.createFromImageData(imgData, frameWidth, h); - frames.push(frame); - } - return frames; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.ImageResizer = { - resize : function (image, targetWidth, targetHeight, smoothingEnabled) { - var canvas = pskl.CanvasUtils.createCanvas(targetWidth, targetHeight); - var context = canvas.getContext('2d'); - context.save(); - - if (!smoothingEnabled) { - pskl.CanvasUtils.disableImageSmoothing(canvas); - } - - context.translate(canvas.width / 2, canvas.height / 2); - context.scale(targetWidth / image.width, targetHeight / image.height); - context.drawImage(image, -image.width / 2, -image.height / 2); - context.restore(); - - return canvas; - }, - - /** - * Manual implementation of resize using a nearest neighbour algorithm - * It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d. - * But it can be useful if : - * - IE < 11 (doesn't support msDisableImageSmoothing) - * - need to display a gap between pixel - * - * @param {Canvas2d} source original image to be resized, as a 2d canvas - * @param {Number} zoom ratio between desired dim / source dim - * @param {Number} margin gap to be displayed between pixels - * @param {String} color or the margin (will be transparent if not provided) - * @return {Canvas2d} the resized canvas - */ - resizeNearestNeighbour : function (source, zoom, margin, marginColor) { - margin = margin || 0; - var canvas = pskl.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height); - var context = canvas.getContext('2d'); - - var imgData = pskl.CanvasUtils.getImageDataFromCanvas(source); - - var yRanges = {}, - xOffset = 0, - yOffset = 0, - xRange, - yRange; - // Draw the zoomed-up pixels to a different canvas context - for (var x = 0; x < source.width; x++) { - // Calculate X Range - xRange = Math.floor((x + 1) * zoom) - xOffset; - - for (var y = 0; y < source.height; y++) { - // Calculate Y Range - if (!yRanges[y + ""]) { - // Cache Y Range - yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset; - } - yRange = yRanges[y + ""]; - - var i = (y * source.width + x) * 4; - var r = imgData[i]; - var g = imgData[i + 1]; - var b = imgData[i + 2]; - var a = imgData[i + 3]; - - context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")"; - context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin); - - if (margin && marginColor) { - context.fillStyle = marginColor; - context.fillRect(xOffset + xRange - margin, yOffset, margin, yRange); - context.fillRect(xOffset, yOffset + yRange - margin, xRange, margin); - } - - yOffset += yRange; - } - yOffset = 0; - xOffset += xRange; - } - return canvas; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.PixelUtils = { - - getRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": x, "row": y}); - } - } - - return pixels; - }, - - getBoundRectanglePixels : function (x0, y0, x1, y1) { - var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var pixels = []; - // Creating horizontal sides of the rectangle: - for(var x = rectangle.x0; x <= rectangle.x1; x++) { - pixels.push({"col": x, "row": rectangle.y0}); - pixels.push({"col": x, "row": rectangle.y1}); - } - - // Creating vertical sides of the rectangle: - for(var y = rectangle.y0; y <= rectangle.y1; y++) { - pixels.push({"col": rectangle.x0, "row": y}); - pixels.push({"col": rectangle.x1, "row": y}); - } - - return pixels; - }, - - /** - * Return an object of ordered rectangle coordinate. - * In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner - * @private - */ - getOrderedRectangleCoordinates : function (x0, y0, x1, y1) { - return { - x0 : Math.min(x0, x1), - y0 : Math.min(y0, y1), - x1 : Math.max(x0, x1), - y1 : Math.max(y0, y1) - }; - }, - - /** - * Return the list of pixels that would have been filled by a paintbucket tool applied - * on pixel at coordinate (x,y). - * This function is not altering the Frame object argument. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * - * @return an array of the pixel coordinates paint with the replacement color - */ - getSimilarConnectedPixelsFromFrame: function(frame, col, row) { - // To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm - // in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels - // and are as well connected. - var fakeFrame = frame.clone(); // We just want to - var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color. - var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor); - - return paintedPixels; - }, - - /** - * Apply the paintbucket tool in a frame at the (col, row) initial position - * with the replacement color. - * - * @param frame pskl.model.Frame The frame target in which we want to paintbucket - * @param col number Column coordinate in the frame - * @param row number Row coordinate in the frame - * @param replacementColor string Hexadecimal color used to fill the area - * - * @return an array of the pixel coordinates paint with the replacement color - */ - paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) { - /** - * Queue linear Flood-fill (node, target-color, replacement-color): - * 1. Set Q to the empty queue. - * 2. If the color of node is not equal to target-color, return. - * 3. Add node to Q. - * 4. For each element n of Q: - * 5. If the color of n is equal to target-color: - * 6. Set w and e equal to n. - * 7. Move w to the west until the color of the node to the west of w no longer matches target-color. - * 8. Move e to the east until the color of the node to the east of e no longer matches target-color. - * 9. Set the color of nodes between w and e to replacement-color. - * 10. For each node n between w and e: - * 11. If the color of the node to the north of n is target-color, add that node to Q. - * 12. If the color of the node to the south of n is target-color, add that node to Q. - * 13. Continue looping until Q is exhausted. - * 14. Return. - */ - var paintedPixels = []; - var queue = []; - var dy = [-1, 0, 1, 0]; - var dx = [0, 1, 0, -1]; - var targetColor; - try { - targetColor = frame.getPixel(col, row); - } catch(e) { - // Frame out of bound exception. - } - - if(targetColor == replacementColor) { - return; - } - - - queue.push({"col": col, "row": row}); - var loopCount = 0; - var cellCount = frame.getWidth() * frame.getHeight(); - while(queue.length > 0) { - loopCount ++; - - var currentItem = queue.pop(); - frame.setPixel(currentItem.col, currentItem.row, replacementColor); - paintedPixels.push({"col": currentItem.col, "row": currentItem.row }); - - for (var i = 0; i < 4; i++) { - var nextCol = currentItem.col + dx[i]; - var nextRow = currentItem.row + dy[i]; - try { - if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) { - queue.push({"col": nextCol, "row": nextRow }); - } - } catch(e) { - // Frame out of bound exception. - } - } - - // Security loop breaker: - if(loopCount > 10 * cellCount) { - console.log("loop breaker called"); - break; - } - } - return paintedPixels; - }, - - /** - * Calculate and return the maximal zoom level to display a picture in a given container. - * - * @param container jQueryObject Container where the picture should be displayed - * @param number pictureHeight height in pixels of the picture to display - * @param number pictureWidth width in pixels of the picture to display - * @return number maximal zoom - */ - calculateZoomForContainer : function (container, pictureHeight, pictureWidth) { - return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.PiskelFileUtils = { - /** - * Load a piskel from a piskel file. - * After deserialization is successful, the provided success callback will be called. - * Success callback is expected to handle 3 arguments : (piskel:Piskel, descriptor:PiskelDescriptor, fps:Number) - * @param {File} file the .piskel file to load - * @param {Function} onSuccess Called if the deserialization of the piskel is successful - * @param {Function} onError NOT USED YET - */ - loadFromFile : function (file, onSuccess, onError) { - pskl.utils.FileUtils.readFile(file, function (content) { - var rawPiskel = pskl.utils.Base64.toText(content); - var serializedPiskel = JSON.parse(rawPiskel); - var fps = serializedPiskel.piskel.fps; - var descriptor = new pskl.model.piskel.Descriptor(serializedPiskel.piskel.name, serializedPiskel.piskel.description, true); - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - onSuccess(piskel, descriptor, fps); - }); - }); - } - }; -})();;(function () { - var ns = $.namespace("pskl.utils"); - var templates = {}; - - ns.Template = { - get : function (templateId) { - if (!templates[templateId]) { - var template = document.getElementById(templateId); - if (template) { - templates[templateId] = template.innerHTML; - } else { - console.error("Could not find template for id :", templateId); - } - } - return templates[templateId]; - }, - - createFromHTML : function (html) { - var dummyEl = document.createElement("div"); - dummyEl.innerHTML = html; - return dummyEl.children[0]; - }, - - getAndReplace : function (templateId, dict) { - var result = ""; - var tpl = pskl.utils.Template.get(templateId); - if (tpl) { - result = pskl.utils.Template.replace(tpl, dict); - } - return result; - }, - - replace : function (template, dict) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - var value = dict[key]; - - // special boolean keys keys key:default - // if the value is a boolean, use default as value - if (key.indexOf(':') !== -1) { - if (value === true) { - value = key.split(':')[1]; - } else if (value === false) { - value = ''; - } - } - template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value); - } - } - return template; - } - }; -})();;(function () { - var ns = $.namespace("pskl"); - - ns.UserSettings = { - GRID_WIDTH : 'GRID_WIDTH', - CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', - SELECTED_PALETTE : 'SELECTED_PALETTE', - TILED_PREVIEW : 'TILED_PREVIEW', - ONION_SKIN : 'ONION_SKIN', - LAYER_PREVIEW : 'LAYER_PREVIEW', - - KEY_TO_DEFAULT_VALUE_MAP_ : { - 'GRID_WIDTH' : 0, - 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', - 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, - 'TILED_PREVIEW' : false, - 'ONION_SKIN' : false, - 'LAYER_PREVIEW' : true - }, - - /** - * @private - */ - cache_ : {}, - - /** - * Static method to access a user defined settings value ot its default - * value if not defined yet. - */ - get : function (key) { - this.checkKeyValidity_(key); - if (!(key in this.cache_)) { - var storedValue = this.readFromLocalStorage_(key); - if (typeof storedValue !== 'undefined' && storedValue !== null) { - this.cache_[key] = storedValue; - } else { - this.cache_[key] = this.readFromDefaults_(key); - } - } - return this.cache_[key]; - }, - - set : function (key, value) { - this.checkKeyValidity_(key); - this.cache_[key] = value; - this.writeToLocalStorage_(key, value); - - $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); - }, - - /** - * @private - */ - readFromLocalStorage_ : function(key) { - var value = window.localStorage[key]; - if (typeof value != "undefined") { - value = JSON.parse(value); - } - return value; - }, - - /** - * @private - */ - writeToLocalStorage_ : function(key, value) { - // TODO(grosbouddha): Catch storage exception here. - window.localStorage[key] = JSON.stringify(value); - }, - - /** - * @private - */ - readFromDefaults_ : function (key) { - return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; - }, - - /** - * @private - */ - checkKeyValidity_ : function(key) { - if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { - // TODO(grosbouddha): Define error catching strategy and throw exception from here. - console.log("UserSettings key <"+ key +"> not find in supported keys."); - } - } - }; -})();;(function(){ - var ns = $.namespace('pskl.utils'); - - var s4 = function () { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - - ns.Uuid = { - generate : function () { - return 'ss-s-s-s-sss'.replace(/s/g, function () { - return s4(); - }); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - ns.Xhr = { - get : function (url, success, error) { - var xhr = ns.Xhr.xhr_(url, 'GET', success, error); - xhr.send(); - }, - - post : function (url, data, success, error) { - var xhr = ns.Xhr.xhr_(url, 'POST', success, error); - var formData = new FormData(); - - if (typeof data == 'object') { - for (var key in data) { - if (data.hasOwnProperty(key)) { - formData.append(key, data[key]); - } - } - } - - xhr.send(formData); - }, - - xhr_ : function (url, method, success, error) { - success = success || function (){}; - error = error || function (){}; - - var xhr = new XMLHttpRequest(); - xhr.open(method, url, true); - - xhr.onload = function(e) { - if (this.status == 200) { - success(this); - } else { - this.onerror(this, e); - } - }; - - xhr.onerror = function(e) { - error(e); - }; - - return xhr; - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils'); - - ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); - }, - - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var renderer = new pskl.rendering.FramesheetRenderer(frames); - var layerToSerialize = { - name : layer.getName(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return f.pixels;}); - return layerToSerialize; - } else { - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); - } - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.utils.serialization'); - - ns.Deserializer = function (data, callback) { - this.layersToLoad_ = 0; - this.data_ = data; - this.callback_ = callback; - this.piskel_ = null; - }; - - ns.Deserializer.deserialize = function (data, callback) { - var deserializer; - if (data.modelVersion == Constants.MODEL_VERSION) { - deserializer = new ns.Deserializer(data, callback); - } else if (data.modelVersion == 1) { - deserializer = new ns.backward.Deserializer_v1(data, callback); - } else { - deserializer = new ns.backward.Deserializer_v0(data, callback); - } - deserializer.deserialize(); - }; - - ns.Deserializer.prototype.deserialize = function (name) { - var data = this.data_; - var piskelData = data.piskel; - name = name || 'Deserialized piskel'; - - var descriptor = new pskl.model.piskel.Descriptor(name, ''); - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - this.layersToLoad_ = piskelData.layers.length; - if (piskelData.expanded) { - piskelData.layers.forEach(this.loadExpandedLayer.bind(this)); - } else { - piskelData.layers.forEach(this.deserializeLayer.bind(this)); - } - }; - - ns.Deserializer.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - - // 1 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 2 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); - // 6 - add each image to the layer - this.addFramesToLayer(frames, layer); - }.bind(this); - - // 3 - set the source of the image - image.src = base64PNG; - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.loadExpandedLayer = function (layerData) { - var layer = new pskl.model.Layer(layerData.name); - var frames = layerData.grids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - this.addFramesToLayer(frames, layer); - - // 4 - return a pointer to the new layer instance - return layer; - }; - - ns.Deserializer.prototype.addFramesToLayer = function (frames, layer) { - frames.forEach(layer.addFrame.bind(layer)); - - this.piskel_.addLayer(layer); - this.onLayerLoaded_(); - }; - - ns.Deserializer.prototype.onLayerLoaded_ = function () { - this.layersToLoad_ = this.layersToLoad_ - 1; - if (this.layersToLoad_ === 0) { - this.callback_(this.piskel_); - } - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v0 = function (data, callback) { - this.data_ = data; - this.callback_ = callback; - }; - - ns.Deserializer_v0.prototype.deserialize = function () { - var pixelGrids = this.data_; - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - - this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor)); - }; -})();;(function () { - var ns = $.namespace('pskl.utils.serialization.backward'); - - ns.Deserializer_v1 = function (data, callback) { - this.callback_ = callback; - this.data_ = data; - }; - - ns.Deserializer_v1.prototype.deserialize = function () { - var piskelData = this.data_.piskel; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }.bind(this)); - - this.callback_(piskel); - }; - - ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = this.deserializeFrame(serializedFrame); - layer.addFrame(frame); - }.bind(this)); - - return layer; - }; - - ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }; -})();;(function () { - var worker = function () { - (function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.setPreserveColors(a.preserveColors),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.setPreserveColors=function(a){this.preserveColors=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var h=this.pixels.length,d=h/3;this.indexedPixels=new Uint8Array(d);var a;this.preserveColors?a=new g(this.pixels,this.sample):a=new f(this.pixels,this.sample),a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new h(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/SimpleQuant.js',function(b,d,e,f){function a(a,b,c){return[a,b,c].join('.')}function c(b){this.pixels=b,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){var h=this.pixels.length/3,b=0;for(var c=0;c>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<this.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js -;( function( window ) { 'use strict'; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; -}; - -Stream.prototype.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return this.data.charCodeAt(this.pos++) & 0xFF; -}; - -Stream.prototype.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; -}; - -Stream.prototype.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; -}; - -Stream.prototype.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; -}; - -var SuperGIF = window.SuperGIF = window.SuperGIF || {}; -SuperGIF.Stream = Stream; - -})( window ); - -/* - SuperGif - - Example usage: - - - - - - Image tag attributes: - - data-animated-src - If this url is specified, it's loaded into the player instead of src. - This allows a preview frame to be shown until animated gif data is streamed into the canvas - - Constructor options args - - gif Required. The DOM element of an img tag. - - Instance methods - - // loading - load( callback ) Loads the gif into a canvas element and then calls callback if one is passed - - For additional customization (viewport inside iframe) these params may be passed: - c_w, c_h - width and height of canvas - vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport - - A bonus: few articles to understand what is going on - http://enthusiasms.org/post/16976438906 - http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546 - -*/ - -( function( window ) { 'use strict'; - -// Generic functions -var bitsToNum = function (ba) { - return ba.reduce(function (s, n) { - return s * 2 + n; - }, 0); -}; - -var byteToBitArr = function (bite) { - var a = []; - for (var i = 7; i >= 0; i--) { - a.push( !! (bite & (1 << i))); - } - return a; -}; - -// Stream -/** - * @constructor - */ -// Make compiler happy. -var Stream = function (data) { - this.data = data; - this.len = this.data.length; - this.pos = 0; - - this.readByte = function () { - if (this.pos >= this.data.length) { - throw new Error('Attempted to read past end of stream.'); - } - return data.charCodeAt(this.pos++) & 0xFF; - }; - - this.readBytes = function (n) { - var bytes = []; - for (var i = 0; i < n; i++) { - bytes.push(this.readByte()); - } - return bytes; - }; - - this.read = function (n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += String.fromCharCode(this.readByte()); - } - return s; - }; - - this.readUnsigned = function () { // Little-endian. - var a = this.readBytes(2); - return (a[1] << 8) + a[0]; - }; -}; - -var lzwDecode = function (minCodeSize, data) { - // TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String? - var pos = 0; // Maybe this streaming thing should be merged with the Stream? - var readCode = function (size) { - var code = 0; - for (var i = 0; i < size; i++) { - if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) { - code |= 1 << i; - } - pos++; - } - return code; - }; - - var output = []; - - var clearCode = 1 << minCodeSize; - var eoiCode = clearCode + 1; - - var codeSize = minCodeSize + 1; - - var dict = []; - - var clear = function () { - dict = []; - codeSize = minCodeSize + 1; - for (var i = 0; i < clearCode; i++) { - dict[i] = [i]; - } - dict[clearCode] = []; - dict[eoiCode] = null; - - }; - - var code; - var last; - - while (true) { - last = code; - code = readCode(codeSize); - - if (code === clearCode) { - clear(); - continue; - } - if (code === eoiCode) break; - - if (code < dict.length) { - if (last !== clearCode) { - dict.push(dict[last].concat(dict[code][0])); - } - } - else { - if (code !== dict.length) throw new Error('Invalid LZW code.'); - dict.push(dict[last].concat(dict[last][0])); - } - output.push.apply(output, dict[code]); - - if (dict.length === (1 << codeSize) && codeSize < 12) { - // If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long. - codeSize++; - } - } - - // I don't know if this is technically an error, but some GIFs do it. - //if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.'); - return output; -}; - - -// The actual parsing; returns an object with properties. -var parseGIF = function (st, handler) { - handler || (handler = {}); - - // LZW (GIF-specific) - var parseCT = function (entries) { // Each entry is 3 bytes, for RGB. - var ct = []; - for (var i = 0; i < entries; i++) { - ct.push(st.readBytes(3)); - } - return ct; - }; - - var readSubBlocks = function () { - var size, data; - data = ''; - do { - size = st.readByte(); - data += st.read(size); - } while (size !== 0); - return data; - }; - - var parseHeader = function () { - var hdr = {}; - hdr.sig = st.read(3); - hdr.ver = st.read(3); - if (hdr.sig !== 'GIF') { - handler.onError(); // XXX: This should probably be handled more nicely. - throw new Error('Not a GIF file.'); - } - hdr.width = st.readUnsigned(); - hdr.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - hdr.gctFlag = bits.shift(); - hdr.colorRes = bitsToNum(bits.splice(0, 3)); - hdr.sorted = bits.shift(); - hdr.gctSize = bitsToNum(bits.splice(0, 3)); - - hdr.bgColor = st.readByte(); - hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64 - if (hdr.gctFlag) { - hdr.gct = parseCT(1 << (hdr.gctSize + 1)); - } - handler.hdr && handler.hdr(hdr); - }; - - var parseExt = function (block) { - var parseGCExt = function (block) { - var blockSize = st.readByte(); // Always 4 - var bits = byteToBitArr(st.readByte()); - block.reserved = bits.splice(0, 3); // Reserved; should be 000. - block.disposalMethod = bitsToNum(bits.splice(0, 3)); - block.userInput = bits.shift(); - block.transparencyGiven = bits.shift(); - - block.delayTime = st.readUnsigned(); - - block.transparencyIndex = st.readByte(); - - block.terminator = st.readByte(); - - handler.gce && handler.gce(block); - }; - - var parseComExt = function (block) { - block.comment = readSubBlocks(); - handler.com && handler.com(block); - }; - - var parsePTExt = function (block) { - // No one *ever* uses this. If you use it, deal with parsing it yourself. - var blockSize = st.readByte(); // Always 12 - block.ptHeader = st.readBytes(12); - block.ptData = readSubBlocks(); - handler.pte && handler.pte(block); - }; - - var parseAppExt = function (block) { - var parseNetscapeExt = function (block) { - var blockSize = st.readByte(); // Always 3 - block.unknown = st.readByte(); // ??? Always 1? What is this? - block.iterations = st.readUnsigned(); - block.terminator = st.readByte(); - handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block); - }; - - var parseUnknownAppExt = function (block) { - block.appData = readSubBlocks(); - // FIXME: This won't work if a handler wants to match on any identifier. - handler.app && handler.app[block.identifier] && handler.app[block.identifier](block); - }; - - var blockSize = st.readByte(); // Always 11 - block.identifier = st.read(8); - block.authCode = st.read(3); - switch (block.identifier) { - case 'NETSCAPE': - parseNetscapeExt(block); - break; - default: - parseUnknownAppExt(block); - break; - } - }; - - var parseUnknownExt = function (block) { - block.data = readSubBlocks(); - handler.unknown && handler.unknown(block); - }; - - block.label = st.readByte(); - switch (block.label) { - case 0xF9: - block.extType = 'gce'; - parseGCExt(block); - break; - case 0xFE: - block.extType = 'com'; - parseComExt(block); - break; - case 0x01: - block.extType = 'pte'; - parsePTExt(block); - break; - case 0xFF: - block.extType = 'app'; - parseAppExt(block); - break; - default: - block.extType = 'unknown'; - parseUnknownExt(block); - break; - } - }; - - var parseImg = function (img) { - var deinterlace = function (pixels, width) { - // Of course this defeats the purpose of interlacing. And it's *probably* - // the least efficient way it's ever been implemented. But nevertheless... - var newPixels = new Array(pixels.length); - var rows = pixels.length / width; - var cpRow = function (toRow, fromRow) { - var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); - newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); - }; - - // See appendix E. - var offsets = [0, 4, 2, 1]; - var steps = [8, 8, 4, 2]; - - var fromRow = 0; - for (var pass = 0; pass < 4; pass++) { - for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { - cpRow(toRow, fromRow) - fromRow++; - } - } - - return newPixels; - }; - - img.leftPos = st.readUnsigned(); - img.topPos = st.readUnsigned(); - img.width = st.readUnsigned(); - img.height = st.readUnsigned(); - - var bits = byteToBitArr(st.readByte()); - img.lctFlag = bits.shift(); - img.interlaced = bits.shift(); - img.sorted = bits.shift(); - img.reserved = bits.splice(0, 2); - img.lctSize = bitsToNum(bits.splice(0, 3)); - - if (img.lctFlag) { - img.lct = parseCT(1 << (img.lctSize + 1)); - } - - img.lzwMinCodeSize = st.readByte(); - - var lzwData = readSubBlocks(); - - img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData); - - if (img.interlaced) { // Move - img.pixels = deinterlace(img.pixels, img.width); - } - - handler.img && handler.img(img); - }; - - var parseBlock = function () { - var block = {}; - block.sentinel = st.readByte(); - - switch (String.fromCharCode(block.sentinel)) { // For ease of matching - case '!': - block.type = 'ext'; - parseExt(block); - break; - case ',': - block.type = 'img'; - parseImg(block); - break; - case ';': - block.type = 'eof'; - handler.eof && handler.eof(block); - break; - default: - return handler.onError(new Error('Unknown block: 0x' + block.sentinel.toString(16))); // TODO: Pad this with a 0. - } - - if (block.type !== 'eof') { - setTimeout(parseBlock, 0); - } - }; - - var parse = function () { - parseHeader(); - setTimeout(parseBlock, 0); - }; - - parse(); -}; - - -var SuperGif = function ( opts ) { - var options = { - //viewport position - vp_l: 0, - vp_t: 0, - vp_w: null, - vp_h: null, - //canvas sizes - c_w: null, - c_h: null - }; - for (var i in opts ) { options[i] = opts[i] } - if (options.vp_w && options.vp_h) options.is_vp = true; - - var stream; - var hdr; - - var loadError = null; - var loading = false; - - var transparency = null; - var delay = null; - var disposalMethod = null; - var disposalRestoreFromIdx = 0; - var lastDisposalMethod = null; - var frame = null; - var lastImg = null; - - var frames = []; - - var gif = options.gif; - - var clear = function () { - transparency = null; - delay = null; - lastDisposalMethod = disposalMethod; - disposalMethod = null; - frame = null; - }; - - // XXX: There's probably a better way to handle catching exceptions when - // callbacks are involved. - var doParse = function () { - try { - parseGIF(stream, handler); - } - catch (err) { - doLoadError('parse'); - } - }; - - var setSizes = function(w, h) { - tmpCanvas.width = w; - tmpCanvas.height = h; - tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); - } - - var doLoadError = function (originOfError) { - - - loadError = originOfError; - hdr = { - width: gif.width, - height: gif.height - }; // Fake header. - frames = []; - }; - - var doHdr = function (_hdr) { - hdr = _hdr; - setSizes(hdr.width, hdr.height) - }; - - var doGCE = function (gce) { - pushFrame(); - clear(); - transparency = gce.transparencyGiven ? gce.transparencyIndex : null; - delay = gce.delayTime; - disposalMethod = gce.disposalMethod; - // We don't have much to do with the rest of GCE. - }; - - var pushFrame = function () { - if (!frame) return; - frames.push({ - data: frame.getImageData(0, 0, hdr.width, hdr.height), - delay: delay - }); - }; - - // flag for drawing initial frame - var isInitFrameDrawn = false; - - var doImg = function (img) { - if (!frame) frame = tmpCanvas.getContext('2d'); - - var currIdx = frames.length; - - //ct = color table, gct = global color table - var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists? - - /* - Disposal method indicates the way in which the graphic is to - be treated after being displayed. - - Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - - Importantly, "previous" means the frame state - after the last disposal of method 0, 1, or 2. - */ - if (currIdx > 0) { - if (lastDisposalMethod === 3) { - // Restore to previous - frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0); - } else { - disposalRestoreFromIdx = currIdx - 1; - } - - if (lastDisposalMethod === 2) { - // Restore to background color - // Browser implementations historically restore to transparent; we do the same. - // http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079 - frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height); - } - } - // else, Undefined/Do not dispose. - // frame contains final pixel data from the last frame; do nothing - - //Get existing pixels for img region after applying disposal method - var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height); - //apply color table colors - var cdd = imgData.data; - img.pixels.forEach(function (pixel, i) { - // imgData.data === [R,G,B,A,R,G,B,A,...] - if (pixel !== transparency) { - cdd[i * 4 + 0] = ct[pixel][0]; - cdd[i * 4 + 1] = ct[pixel][1]; - cdd[i * 4 + 2] = ct[pixel][2]; - cdd[i * 4 + 3] = 255; // Opaque. - } - }); - - frame.putImageData(imgData, img.leftPos, img.topPos); - - lastImg = img; - }; - - var doNothing = function () {}; - /** - * @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency. - * Note that this means that the text will be unsynchronized with the progress bar on non-frames; - * but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly. - */ - var handler = { - hdr: doHdr, - gce: doGCE, - // I guess that's all for now. - // app: { - // // TODO: Is there much point in actually supporting iterations? - // NETSCAPE: withProgress(doNothing) - // }, - img: doImg, - eof: function (block) { - pushFrame(); - loading = false; - if (load_callback) { - load_callback(); - } - }, - - onError : function (error) { - if (error_callback) { - error_callback(); - } - } - }; - - var load_callback = false; - var error_callback = false; - var tmpCanvas = document.createElement('canvas'); - - return { - - load: function (callback) { - - load_callback = callback.success; - error_callback = callback.error; - - loading = true; - - if (gif.src.indexOf('data:') !== -1) { - var data = gif.src.substring(gif.src.indexOf(',')+1); - stream = new Stream(window.atob(data)); - doParse(); - } else { - var h = new XMLHttpRequest(); - h.overrideMimeType('text/plain; charset=x-user-defined'); - h.onload = function(e) { - stream = new Stream(h.responseText); - setTimeout(doParse, 0); - }; - h.onerror = function() { doLoadError('xhr'); }; - h.open('GET', gif.getAttribute('data-animated-src') || gif.src, true); - h.send(); - } - }, - - getFrames : function () { - return frames; - } - }; -}; - - -window.SuperGif = SuperGif; - -})( window );;/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library zlib.js released under the following license : -zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;(d=2*e+2,!(d>=this.length))&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ -(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)});;// Spectrum Colorpicker v1.1.2 -// https://github.com/bgrins/spectrum -// Author: Brian Grinstead -// License: MIT - -(function (window, $, undefined) { - var defaultOpts = { - - // Callbacks - beforeShow: noop, - move: noop, - change: noop, - show: noop, - hide: noop, - - // Options - color: false, - flat: false, - showInput: false, - showButtons: true, - clickoutFiresChange: false, - showInitial: false, - showPalette: false, - showPaletteOnly: false, - showSelectionPalette: true, - localStorageKey: false, - appendTo: "body", - maxSelectionSize: 7, - cancelText: "cancel", - chooseText: "choose", - preferredFormat: false, - className: "", - showAlpha: false, - theme: "sp-light", - palette: ['fff', '000'], - selectionPalette: [], - disabled: false - }, - spectrums = [], - IE = !!/msie/i.exec( window.navigator.userAgent ), - rgbaSupport = (function() { - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - var elem = document.createElement('div'); - var style = elem.style; - style.cssText = 'background-color:rgba(0,0,0,.5)'; - return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); - })(), - replaceInput = [ - "
        ", - "
        ", - "
        ", - "
        " - ].join(''), - markup = (function () { - - // IE does not support gradients with multiple stops, so we need to simulate - // that for the rainbow slider with 8 divs that each have a single gradient - var gradientFix = ""; - if (IE) { - for (var i = 1; i <= 6; i++) { - gradientFix += "
        "; - } - } - - return [ - "
        " - ].join(""); - })(); - - function paletteTemplate (p, color, className) { - var html = []; - for (var i = 0; i < p.length; i++) { - var tiny = tinycolor(p[i]); - var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; - c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : ""; - - var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); - html.push(''); - } - return "
        " + html.join('') + "
        "; - } - - function hideAll() { - for (var i = 0; i < spectrums.length; i++) { - if (spectrums[i]) { - spectrums[i].hide(); - } - } - } - - function instanceOptions(o, callbackContext) { - var opts = $.extend({}, defaultOpts, o); - opts.callbacks = { - 'move': bind(opts.move, callbackContext), - 'change': bind(opts.change, callbackContext), - 'show': bind(opts.show, callbackContext), - 'hide': bind(opts.hide, callbackContext), - 'beforeShow': bind(opts.beforeShow, callbackContext) - }; - - return opts; - } - - function spectrum(element, o) { - - var opts = instanceOptions(o, element), - flat = opts.flat, - showSelectionPalette = opts.showSelectionPalette, - localStorageKey = opts.localStorageKey, - theme = opts.theme, - callbacks = opts.callbacks, - resize = throttle(reflow, 10), - visible = false, - dragWidth = 0, - dragHeight = 0, - dragHelperHeight = 0, - slideHeight = 0, - slideWidth = 0, - alphaWidth = 0, - alphaSlideHelperWidth = 0, - slideHelperHeight = 0, - currentHue = 0, - currentSaturation = 0, - currentValue = 0, - currentAlpha = 1, - palette = opts.palette.slice(0), - paletteArray = $.isArray(palette[0]) ? palette : [palette], - selectionPalette = opts.selectionPalette.slice(0), - maxSelectionSize = opts.maxSelectionSize, - draggingClass = "sp-dragging", - shiftMovementDirection = null; - - var doc = element.ownerDocument, - body = doc.body, - boundElement = $(element), - disabled = false, - container = $(markup, doc).addClass(theme), - dragger = container.find(".sp-color"), - dragHelper = container.find(".sp-dragger"), - slider = container.find(".sp-hue"), - slideHelper = container.find(".sp-slider"), - alphaSliderInner = container.find(".sp-alpha-inner"), - alphaSlider = container.find(".sp-alpha"), - alphaSlideHelper = container.find(".sp-alpha-handle"), - textInput = container.find(".sp-input"), - paletteContainer = container.find(".sp-palette"), - initialColorContainer = container.find(".sp-initial"), - cancelButton = container.find(".sp-cancel"), - chooseButton = container.find(".sp-choose"), - isInput = boundElement.is("input"), - shouldReplace = isInput && !flat, - replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className) : $([]), - offsetElement = (shouldReplace) ? replacer : boundElement, - previewElement = replacer.find(".sp-preview-inner"), - initialColor = opts.color || (isInput && boundElement.val()), - colorOnShow = false, - preferredFormat = opts.preferredFormat, - currentPreferredFormat = preferredFormat, - clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange; - - - function applyOptions() { - - if (opts.showPaletteOnly) { - opts.showPalette = true; - } - - container.toggleClass("sp-flat", flat); - container.toggleClass("sp-input-disabled", !opts.showInput); - container.toggleClass("sp-alpha-enabled", opts.showAlpha); - container.toggleClass("sp-buttons-disabled", !opts.showButtons); - container.toggleClass("sp-palette-disabled", !opts.showPalette); - container.toggleClass("sp-palette-only", opts.showPaletteOnly); - container.toggleClass("sp-initial-disabled", !opts.showInitial); - container.addClass(opts.className); - - reflow(); - } - - function initialize() { - - if (IE) { - container.find("*:not(input)").attr("unselectable", "on"); - } - - applyOptions(); - - if (shouldReplace) { - boundElement.after(replacer).hide(); - } - - if (flat) { - boundElement.after(container).hide(); - } - else { - - var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); - if (appendTo.length !== 1) { - appendTo = $("body"); - } - - appendTo.append(container); - } - - if (localStorageKey && window.localStorage) { - - // Migrate old palettes over to new format. May want to remove this eventually. - try { - var oldPalette = window.localStorage[localStorageKey].split(",#"); - if (oldPalette.length > 1) { - delete window.localStorage[localStorageKey]; - $.each(oldPalette, function(i, c) { - addColorToSelectionPalette(c); - }); - } - } - catch(e) { } - - try { - selectionPalette = window.localStorage[localStorageKey].split(";"); - } - catch (e) { } - } - - offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { - if (!disabled) { - toggle(); - } - - e.stopPropagation(); - - if (!$(e.target).is("input")) { - e.preventDefault(); - } - }); - - if(boundElement.is(":disabled") || (opts.disabled === true)) { - disable(); - } - - // Prevent clicks from bubbling up to document. This would cause it to be hidden. - container.click(stopPropagation); - - // Handle user typed input - textInput.change(setFromTextInput); - textInput.bind("paste", function () { - setTimeout(setFromTextInput, 1); - }); - textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); - - cancelButton.text(opts.cancelText); - cancelButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - hide("cancel"); - }); - - chooseButton.text(opts.chooseText); - chooseButton.bind("click.spectrum", function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (isValid()) { - updateOriginalInput(true); - hide(); - } - }); - - draggable(alphaSlider, function (dragX, dragY, e) { - currentAlpha = (dragX / alphaWidth); - if (e.shiftKey) { - currentAlpha = Math.round(currentAlpha * 10) / 10; - } - - move(); - }); - - draggable(slider, function (dragX, dragY) { - currentHue = parseFloat(dragY / slideHeight); - move(); - }, dragStart, dragStop); - - draggable(dragger, function (dragX, dragY, e) { - - // shift+drag should snap the movement to either the x or y axis. - if (!e.shiftKey) { - shiftMovementDirection = null; - } - else if (!shiftMovementDirection) { - var oldDragX = currentSaturation * dragWidth; - var oldDragY = dragHeight - (currentValue * dragHeight); - var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); - - shiftMovementDirection = furtherFromX ? "x" : "y"; - } - - var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; - var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; - - if (setSaturation) { - currentSaturation = parseFloat(dragX / dragWidth); - } - if (setValue) { - currentValue = parseFloat((dragHeight - dragY) / dragHeight); - } - - move(); - - }, dragStart, dragStop); - - if (!!initialColor) { - set(initialColor); - - // In case color was black - update the preview UI and set the format - // since the set function will not run (default color is black). - updateUI(); - currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; - - addColorToSelectionPalette(initialColor); - } - else { - updateUI(); - } - - if (flat) { - show(); - } - - function palletElementClick(e) { - if (e.data && e.data.ignore) { - set($(this).data("color")); - move(); - } - else { - set($(this).data("color")); - updateOriginalInput(true); - move(); - hide(); - } - - return false; - } - - var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; - paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); - initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); - } - - function addColorToSelectionPalette(color) { - if (showSelectionPalette) { - var colorRgb = tinycolor(color).toRgbString(); - if ($.inArray(colorRgb, selectionPalette) === -1) { - selectionPalette.push(colorRgb); - while(selectionPalette.length > maxSelectionSize) { - selectionPalette.shift(); - } - } - - if (localStorageKey && window.localStorage) { - try { - window.localStorage[localStorageKey] = selectionPalette.join(";"); - } - catch(e) { } - } - } - } - - function getUniqueSelectionPalette() { - var unique = []; - var p = selectionPalette; - var paletteLookup = {}; - var rgb; - - if (opts.showPalette) { - - for (var i = 0; i < paletteArray.length; i++) { - for (var j = 0; j < paletteArray[i].length; j++) { - rgb = tinycolor(paletteArray[i][j]).toRgbString(); - paletteLookup[rgb] = true; - } - } - - for (i = 0; i < p.length; i++) { - rgb = tinycolor(p[i]).toRgbString(); - - if (!paletteLookup.hasOwnProperty(rgb)) { - unique.push(p[i]); - paletteLookup[rgb] = true; - } - } - } - - return unique.reverse().slice(0, opts.maxSelectionSize); - } - - function drawPalette() { - - var currentColor = get(); - - var html = $.map(paletteArray, function (palette, i) { - return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i); - }); - - if (selectionPalette) { - html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection")); - } - - paletteContainer.html(html.join("")); - } - - function drawInitial() { - if (opts.showInitial) { - var initial = colorOnShow; - var current = get(); - initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial")); - } - } - - function dragStart() { - if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { - reflow(); - } - container.addClass(draggingClass); - shiftMovementDirection = null; - } - - function dragStop() { - container.removeClass(draggingClass); - } - - function setFromTextInput() { - var tiny = tinycolor(textInput.val()); - if (tiny.ok) { - set(tiny); - } - else { - textInput.addClass("sp-validation-error"); - } - } - - function toggle() { - if (visible) { - hide(); - } - else { - show(); - } - } - - function show() { - var event = $.Event('beforeShow.spectrum'); - - if (visible) { - reflow(); - return; - } - - colorOnShow = get(); - boundElement.trigger(event, [ colorOnShow ]); - - if (callbacks.beforeShow(colorOnShow) === false || event.isDefaultPrevented()) { - return; - } - - // if color has changed - set(colorOnShow); - - hideAll(); - visible = true; - - $(doc).bind("mousedown.spectrum", onMousedown); - - // Piskel-specific : change the color as soon as the user does a mouseup - $(doc).bind("mouseup.spectrum", updateColor); - - $(window).bind("resize.spectrum", resize); - replacer.addClass("sp-active"); - container.removeClass("sp-hidden"); - - if (opts.showPalette) { - drawPalette(); - } - reflow(); - updateUI(); - - drawInitial(); - callbacks.show(colorOnShow); - boundElement.trigger('show.spectrum', [ colorOnShow ]); - } - - function onMousedown (e) { - var target = $(e.target); - var parents = target.parents(); - var isClickOutsideWidget = !parents.is(container) && !target.is(container); - - if (isClickOutsideWidget) { - hide(e); - } - } - - // Piskel-specific (code extracted to method) - function updateColor(e) { - var colorHasChanged = !tinycolor.equals(get(), colorOnShow); - - if (colorHasChanged) { - if (clickoutFiresChange && e !== "cancel") { - updateOriginalInput(true); - } - else { - revert(); - } - } - } - - function hide(e) { - - // Return on right click - if (e && e.type == "click" && e.button == 2) { return; } - - // Return if hiding is unnecessary - if (!visible || flat) { return; } - visible = false; - - $(doc).unbind("mousedown.spectrum", onMousedown); - - // Piskel-specific - $(doc).unbind("mouseup.spectrum", updateColor); - - $(window).unbind("resize.spectrum", resize); - - replacer.removeClass("sp-active"); - container.addClass("sp-hidden"); - - updateColor(e); - - // Piskel-specific - addColorToSelectionPalette(get()); - - callbacks.hide(get()); - boundElement.trigger('hide.spectrum', [ get() ]); - } - - function revert() { - set(colorOnShow, true); - } - - function set(color, ignoreFormatChange) { - if (tinycolor.equals(color, get())) { - return; - } - - var newColor = tinycolor(color); - var newHsv = newColor.toHsv(); - - currentHue = (newHsv.h % 360) / 360; - currentSaturation = newHsv.s; - currentValue = newHsv.v; - currentAlpha = newHsv.a; - - updateUI(); - - if (newColor.ok && !ignoreFormatChange) { - currentPreferredFormat = preferredFormat || newColor.format; - } - } - - function get(opts) { - opts = opts || { }; - return tinycolor.fromRatio({ - h: currentHue, - s: currentSaturation, - v: currentValue, - a: Math.round(currentAlpha * 100) / 100 - }, { format: opts.format || currentPreferredFormat }); - } - - function isValid() { - return !textInput.hasClass("sp-validation-error"); - } - - function move() { - updateUI(); - - callbacks.move(get()); - boundElement.trigger('move.spectrum', [ get() ]); - } - - function updateUI() { - - textInput.removeClass("sp-validation-error"); - - updateHelperLocations(); - - // Update dragger background color (gradients take care of saturation and value). - var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); - dragger.css("background-color", flatColor.toHexString()); - - // Get a format that alpha will be included in (hex and names ignore alpha) - var format = currentPreferredFormat; - if (currentAlpha < 1) { - if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { - format = "rgb"; - } - } - - var realColor = get({ format: format }), - realHex = realColor.toHexString(), - realRgb = realColor.toRgbString(); - - // Update the replaced elements background color (with actual selected color) - if (rgbaSupport || realColor.alpha === 1) { - previewElement.css("background-color", realRgb); - } - else { - previewElement.css("background-color", "transparent"); - previewElement.css("filter", realColor.toFilter()); - } - - if (opts.showAlpha) { - var rgb = realColor.toRgb(); - rgb.a = 0; - var realAlpha = tinycolor(rgb).toRgbString(); - var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; - - if (IE) { - alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); - } - else { - alphaSliderInner.css("background", "-webkit-" + gradient); - alphaSliderInner.css("background", "-moz-" + gradient); - alphaSliderInner.css("background", "-ms-" + gradient); - alphaSliderInner.css("background", gradient); - } - } - - - // Update the text entry input as it changes happen - if (opts.showInput) { - textInput.val(realColor.toString(Constants.PREFERRED_COLOR_FORMAT || format)); - } - - if (opts.showPalette) { - drawPalette(); - } - - drawInitial(); - } - - function updateHelperLocations() { - var s = currentSaturation; - var v = currentValue; - - // Where to show the little circle in that displays your current selected color - var dragX = s * dragWidth; - var dragY = (dragHeight) - (v * dragHeight); - dragX = Math.max( - -dragHelperHeight/2, - Math.min(dragWidth - dragHelperHeight/2, dragX - dragHelperHeight/2) - ); - dragY = Math.max( - -dragHelperHeight/2, - Math.min(dragHeight - dragHelperHeight/2, dragY - dragHelperHeight/2) - ); - dragHelper.css({ - "top": dragY, - "left": dragX - }); - - var alphaX = currentAlpha * alphaWidth; - alphaSlideHelper.css({ - "left": alphaX - (alphaSlideHelperWidth / 2) - }); - - // Where to show the bar that displays your current selected hue - var slideY = (currentHue) * slideHeight; - slideHelper.css({ - "top": slideY - (slideHelperHeight/2) - }); - } - - function updateOriginalInput(fireCallback) { - var color = get(); - - if (isInput) { - boundElement.val(color.toString(currentPreferredFormat)); - } - - var hasChanged = !tinycolor.equals(color, colorOnShow); - colorOnShow = color; - - // Update the selection palette with the current color - - // Piskel-specific : commented-out, palette update is done on hide - // addColorToSelectionPalette(color); - - if (fireCallback && hasChanged) { - callbacks.change(color); - boundElement.trigger('change', [ color ]); - } - } - - function reflow() { - dragWidth = dragger.width(); - dragHeight = dragger.height(); - dragHelperHeight = dragHelper.height() + 4; - slideWidth = slider.width(); - slideHeight = slider.height(); - slideHelperHeight = slideHelper.height() + 4; - alphaWidth = alphaSlider.width(); - alphaSlideHelperWidth = alphaSlideHelper.width(); - - if (!flat) { - container.css("position", "absolute"); - container.offset(getOffset(container, offsetElement)); - } - - updateHelperLocations(); - } - - function destroy() { - boundElement.show(); - offsetElement.unbind("click.spectrum touchstart.spectrum"); - container.remove(); - replacer.remove(); - spectrums[spect.id] = null; - } - - function option(optionName, optionValue) { - if (optionName === undefined) { - return $.extend({}, opts); - } - if (optionValue === undefined) { - return opts[optionName]; - } - - opts[optionName] = optionValue; - applyOptions(); - } - - function enable() { - disabled = false; - boundElement.attr("disabled", false); - offsetElement.removeClass("sp-disabled"); - } - - function disable() { - hide(); - disabled = true; - boundElement.attr("disabled", true); - offsetElement.addClass("sp-disabled"); - } - - initialize(); - - var spect = { - show: show, - hide: hide, - toggle: toggle, - reflow: reflow, - option: option, - enable: enable, - disable: disable, - set: function (c) { - set(c); - updateOriginalInput(); - }, - get: get, - destroy: destroy, - container: container - }; - - spect.id = spectrums.push(spect) - 1; - - return spect; - } - - /** - * checkOffset - get the offset below/above and left/right element depending on screen position - * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js - */ - function getOffset(picker, input) { - var extraY = 0; - var dpWidth = picker.outerWidth(); - var dpHeight = picker.outerHeight(); - var inputHeight = input.outerHeight(); - var doc = picker[0].ownerDocument; - var docElem = doc.documentElement; - var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); - var viewHeight = docElem.clientHeight + $(doc).scrollTop(); - var offset = input.offset(); - offset.top += inputHeight; - - if (Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth))) { - offset.left -= Math.abs(offset.left + dpWidth - viewWidth); - picker.attr('data-x-position','right'); - } else { - offset.left -= 0; - picker.attr('data-x-position','left'); - } - - if (Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight))) { - offset.top -= Math.abs(dpHeight + inputHeight - extraY); - picker.attr('data-y-position','top'); - } else { - offset.top -= extraY; - picker.attr('data-y-position','bottom'); - } - - return offset; - } - - /** - * noop - do nothing - */ - function noop() { - - } - - /** - * stopPropagation - makes the code only doing this a little easier to read in line - */ - function stopPropagation(e) { - e.stopPropagation(); - } - - /** - * Create a function bound to a given object - * Thanks to underscore.js - */ - function bind(func, obj) { - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - return function () { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - } - - /** - * Lightweight drag helper. Handles containment within the element, so that - * when dragging, the x is within [0,element.width] and y is within [0,element.height] - */ - function draggable(element, onmove, onstart, onstop) { - onmove = onmove || function () { }; - onstart = onstart || function () { }; - onstop = onstop || function () { }; - var doc = element.ownerDocument || document; - var dragging = false; - var offset = {}; - var maxHeight = 0; - var maxWidth = 0; - var hasTouch = ('ontouchstart' in window); - - var duringDragEvents = {}; - duringDragEvents["selectstart"] = prevent; - duringDragEvents["dragstart"] = prevent; - duringDragEvents["touchmove mousemove"] = move; - duringDragEvents["touchend mouseup"] = stop; - - function prevent(e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function move(e) { - if (dragging) { - // Mouseup happened outside of window - if (IE && document.documentMode < 9 && !e.button) { - return stop(); - } - - var touches = e.originalEvent.touches; - var pageX = touches ? touches[0].pageX : e.pageX; - var pageY = touches ? touches[0].pageY : e.pageY; - - var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - if (hasTouch) { - // Stop scrolling in iOS - prevent(e); - } - - onmove.apply(element, [dragX, dragY, e]); - } - } - function start(e) { - var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); - var touches = e.originalEvent.touches; - - if (!rightclick && !dragging) { - if (onstart.apply(element, arguments) !== false) { - dragging = true; - maxHeight = $(element).height(); - maxWidth = $(element).width(); - offset = $(element).offset(); - - $(doc).bind(duringDragEvents); - $(doc.body).addClass("sp-dragging"); - - if (!hasTouch) { - move(e); - } - - prevent(e); - } - } - } - function stop() { - if (dragging) { - $(doc).unbind(duringDragEvents); - $(doc.body).removeClass("sp-dragging"); - onstop.apply(element, arguments); - } - dragging = false; - } - - $(element).bind("touchstart mousedown", start); - } - - function throttle(func, wait, debounce) { - var timeout; - return function () { - var context = this, args = arguments; - var throttler = function () { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - } - - - function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} - - /** - * Define a jQuery plugin - */ - var dataID = "spectrum.id"; - $.fn.spectrum = function (opts, extra) { - - if (typeof opts == "string") { - - var returnValue = this; - var args = Array.prototype.slice.call( arguments, 1 ); - - this.each(function () { - var spect = spectrums[$(this).data(dataID)]; - if (spect) { - - var method = spect[opts]; - if (!method) { - throw new Error( "Spectrum: no such method: '" + opts + "'" ); - } - - if (opts == "get") { - returnValue = spect.get(); - } - else if (opts == "container") { - returnValue = spect.container; - } - else if (opts == "option") { - returnValue = spect.option.apply(spect, args); - } - else if (opts == "destroy") { - spect.destroy(); - $(this).removeData(dataID); - } - else { - method.apply(spect, args); - } - } - }); - - return returnValue; - } - - // Initializing a new instance of spectrum - return this.spectrum("destroy").each(function () { - var spect = spectrum(this, opts); - $(this).data(dataID, spect.id); - }); - }; - - $.fn.spectrum.load = true; - $.fn.spectrum.loadOpts = {}; - $.fn.spectrum.draggable = draggable; - $.fn.spectrum.defaults = defaultOpts; - - $.spectrum = { }; - $.spectrum.localization = { }; - $.spectrum.palettes = { }; - - $.fn.spectrum.processNativeColorInputs = function () { - var colorInput = $("")[0]; - var supportsColor = colorInput.type === "color" && colorInput.value != "!"; - - if (!supportsColor) { - $("input[type=color]").spectrum({ - preferredFormat: "hex6" - }); - } - }; - - // TinyColor v0.9.16 - // https://github.com/bgrins/TinyColor - // 2013-08-10, Brian Grinstead, MIT License - - (function() { - - var trimLeft = /^[\s,#]+/, - trimRight = /\s+$/, - tinyCounter = 0, - math = Math, - mathRound = math.round, - mathMin = math.min, - mathMax = math.max, - mathRandom = math.random; - - function tinycolor (color, opts) { - - color = (color) ? color : ''; - opts = opts || { }; - - // If input is already a tinycolor, return itself - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } - - var rgb = inputToRGB(color); - var r = rgb.r, - g = rgb.g, - b = rgb.b, - a = rgb.a, - roundA = mathRound(100*a) / 100, - format = opts.format || rgb.format; - - // Don't let the range of [0,255] come back in [0,1]. - // Potentially lose a little bit of precision here, but will fix issues where - // .5 gets interpreted as half of the total, instead of half of 1 - // If it was supposed to be 128, this was already taken care of by `inputToRgb` - if (r < 1) { r = mathRound(r); } - if (g < 1) { g = mathRound(g); } - if (b < 1) { b = mathRound(b); } - - return { - ok: rgb.ok, - format: format, - _tc_id: tinyCounter++, - alpha: a, - getAlpha: function() { - return a; - }, - setAlpha: function(value) { - a = boundAlpha(value); - roundA = mathRound(100*a) / 100; - }, - toHsv: function() { - var hsv = rgbToHsv(r, g, b); - return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; - }, - toHsvString: function() { - var hsv = rgbToHsv(r, g, b); - var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); - return (a == 1) ? - "hsv(" + h + ", " + s + "%, " + v + "%)" : - "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; - }, - toHsl: function() { - var hsl = rgbToHsl(r, g, b); - return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; - }, - toHslString: function() { - var hsl = rgbToHsl(r, g, b); - var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); - return (a == 1) ? - "hsl(" + h + ", " + s + "%, " + l + "%)" : - "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; - }, - toHex: function(allow3Char) { - return rgbToHex(r, g, b, allow3Char); - }, - toHexString: function(allow3Char) { - return '#' + rgbToHex(r, g, b, allow3Char); - }, - toRgb: function() { - return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; - }, - toRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : - "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; - }, - toPercentageRgb: function() { - return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; - }, - toPercentageRgbString: function() { - return (a == 1) ? - "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : - "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; - }, - toName: function() { - if (a === 0) { - return "transparent"; - } - - return hexNames[rgbToHex(r, g, b, true)] || false; - }, - toFilter: function(secondColor) { - var hex = rgbToHex(r, g, b); - var secondHex = hex; - var alphaHex = Math.round(parseFloat(a) * 255).toString(16); - var secondAlphaHex = alphaHex; - var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; - - if (secondColor) { - var s = tinycolor(secondColor); - secondHex = s.toHex(); - secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16); - } - - return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")"; - }, - toString: function(format) { - var formatSet = !!format; - format = format || this.format; - - var formattedString = false; - var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; - var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); - - if (format === "rgb") { - formattedString = this.toRgbString(); - } - if (format === "prgb") { - formattedString = this.toPercentageRgbString(); - } - if (format === "hex" || format === "hex6") { - formattedString = this.toHexString(); - } - if (format === "hex3") { - formattedString = this.toHexString(true); - } - if (format === "name") { - formattedString = this.toName(); - } - if (format === "hsl") { - formattedString = this.toHslString(); - } - if (format === "hsv") { - formattedString = this.toHsvString(); - } - - if (formatWithAlpha) { - return this.toRgbString(); - } - - return formattedString || this.toHexString(); - } - }; - } - - // If input is an object, force 1 into "1.0" to handle ratios properly - // String input requires "1.0" as input, so 1 will be treated as 1 - tinycolor.fromRatio = function(color, opts) { - if (typeof color == "object") { - var newColor = {}; - for (var i in color) { - if (color.hasOwnProperty(i)) { - if (i === "a") { - newColor[i] = color[i]; - } - else { - newColor[i] = convertToPercentage(color[i]); - } - } - } - color = newColor; - } - - return tinycolor(color, opts); - }; - - // Given a string or object, convert that input to RGB - // Possible string inputs: - // - // "red" - // "#f00" or "f00" - // "#ff0000" or "ff0000" - // "rgb 255 0 0" or "rgb (255, 0, 0)" - // "rgb 1.0 0 0" or "rgb (1, 0, 0)" - // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" - // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" - // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" - // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" - // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" - // - function inputToRGB(color) { - - var rgb = { r: 0, g: 0, b: 0 }; - var a = 1; - var ok = false; - var format = false; - - if (typeof color == "string") { - color = stringInputToObject(color); - } - - if (typeof color == "object") { - if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { - rgb = rgbToRgb(color.r, color.g, color.b); - ok = true; - format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { - color.s = convertToPercentage(color.s); - color.v = convertToPercentage(color.v); - rgb = hsvToRgb(color.h, color.s, color.v); - ok = true; - format = "hsv"; - } - else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { - color.s = convertToPercentage(color.s); - color.l = convertToPercentage(color.l); - rgb = hslToRgb(color.h, color.s, color.l); - ok = true; - format = "hsl"; - } - - if (color.hasOwnProperty("a")) { - a = color.a; - } - } - - a = boundAlpha(a); - - return { - ok: ok, - format: color.format || format, - r: mathMin(255, mathMax(rgb.r, 0)), - g: mathMin(255, mathMax(rgb.g, 0)), - b: mathMin(255, mathMax(rgb.b, 0)), - a: a - }; - } - - - // Conversion Functions - // -------------------- - - // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: - // - - // `rgbToRgb` - // Handle bounds / percentage checking to conform to CSS color spec - // - // *Assumes:* r, g, b in [0, 255] or [0, 1] - // *Returns:* { r, g, b } in [0, 255] - function rgbToRgb(r, g, b){ - return { - r: bound01(r, 255) * 255, - g: bound01(g, 255) * 255, - b: bound01(b, 255) * 255 - }; - } - - // `rgbToHsl` - // Converts an RGB color value to HSL. - // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] - // *Returns:* { h, s, l } in [0,1] - function rgbToHsl(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min) { - h = s = 0; // achromatic - } - else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - return { h: h, s: s, l: l }; - } - - // `hslToRgb` - // Converts an HSL color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hslToRgb(h, s, l) { - var r, g, b; - - h = bound01(h, 360); - s = bound01(s, 100); - l = bound01(l, 100); - - function hue2rgb(p, q, t) { - if(t < 0) t += 1; - if(t > 1) t -= 1; - if(t < 1/6) return p + (q - p) * 6 * t; - if(t < 1/2) return q; - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - - if(s === 0) { - r = g = b = l; // achromatic - } - else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHsv` - // Converts an RGB color value to HSV - // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] - // *Returns:* { h, s, v } in [0,1] - function rgbToHsv(r, g, b) { - - r = bound01(r, 255); - g = bound01(g, 255); - b = bound01(b, 255); - - var max = mathMax(r, g, b), min = mathMin(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max === 0 ? 0 : d / max; - - if(max == min) { - h = 0; // achromatic - } - else { - switch(max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - return { h: h, s: s, v: v }; - } - - // `hsvToRgb` - // Converts an HSV color value to RGB. - // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] - // *Returns:* { r, g, b } in the set [0, 255] - function hsvToRgb(h, s, v) { - - h = bound01(h, 360) * 6; - s = bound01(s, 100); - v = bound01(v, 100); - - var i = math.floor(h), - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod], - g = [t, v, v, q, p, p][mod], - b = [p, p, t, v, v, q][mod]; - - return { r: r * 255, g: g * 255, b: b * 255 }; - } - - // `rgbToHex` - // Converts an RGB color to hex - // Assumes r, g, and b are contained in the set [0, 255] - // Returns a 3 or 6 character hex - function rgbToHex(r, g, b, allow3Char) { - - var hex = [ - pad2(mathRound(r).toString(16)), - pad2(mathRound(g).toString(16)), - pad2(mathRound(b).toString(16)) - ]; - - // Return a 3 character hex if possible - if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { - return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); - } - - return hex.join(""); - } - - // `equals` - // Can be called with any tinycolor input - tinycolor.equals = function (color1, color2) { - if (!color1 || !color2) { return false; } - return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); - }; - tinycolor.random = function() { - return tinycolor.fromRatio({ - r: mathRandom(), - g: mathRandom(), - b: mathRandom() - }); - }; - - - // Modification Functions - // ---------------------- - // Thanks to less.js for some of the basics here - // - - tinycolor.desaturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s -= amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.saturate = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.s += amount / 100; - hsl.s = clamp01(hsl.s); - return tinycolor(hsl); - }; - tinycolor.greyscale = function(color) { - return tinycolor.desaturate(color, 100); - }; - tinycolor.lighten = function(color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l += amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.darken = function (color, amount) { - amount = (amount === 0) ? 0 : (amount || 10); - var hsl = tinycolor(color).toHsl(); - hsl.l -= amount / 100; - hsl.l = clamp01(hsl.l); - return tinycolor(hsl); - }; - tinycolor.complement = function(color) { - var hsl = tinycolor(color).toHsl(); - hsl.h = (hsl.h + 180) % 360; - return tinycolor(hsl); - }; - - - // Combination Functions - // --------------------- - // Thanks to jQuery xColor for some of the ideas behind these - // - - tinycolor.triad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.tetrad = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), - tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) - ]; - }; - tinycolor.splitcomplement = function(color) { - var hsl = tinycolor(color).toHsl(); - var h = hsl.h; - return [ - tinycolor(color), - tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), - tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) - ]; - }; - tinycolor.analogous = function(color, results, slices) { - results = results || 6; - slices = slices || 30; - - var hsl = tinycolor(color).toHsl(); - var part = 360 / slices; - var ret = [tinycolor(color)]; - - for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { - hsl.h = (hsl.h + part) % 360; - ret.push(tinycolor(hsl)); - } - return ret; - }; - tinycolor.monochromatic = function(color, results) { - results = results || 6; - var hsv = tinycolor(color).toHsv(); - var h = hsv.h, s = hsv.s, v = hsv.v; - var ret = []; - var modification = 1 / results; - - while (results--) { - ret.push(tinycolor({ h: h, s: s, v: v})); - v = (v + modification) % 1; - } - - return ret; - }; - - - // Readability Functions - // --------------------- - // - - // `readability` - // Analyze the 2 colors and returns an object with the following properties: - // `brightness`: difference in brightness between the two colors - // `color`: difference in color/hue between the two colors - tinycolor.readability = function(color1, color2) { - var a = tinycolor(color1).toRgb(); - var b = tinycolor(color2).toRgb(); - var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; - var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; - var colorDiff = ( - Math.max(a.r, b.r) - Math.min(a.r, b.r) + - Math.max(a.g, b.g) - Math.min(a.g, b.g) + - Math.max(a.b, b.b) - Math.min(a.b, b.b) - ); - - return { - brightness: Math.abs(brightnessA - brightnessB), - color: colorDiff - }; - }; - - // `readable` - // http://www.w3.org/TR/AERT#color-contrast - // Ensure that foreground and background color combinations provide sufficient contrast. - // *Example* - // tinycolor.readable("#000", "#111") => false - tinycolor.readable = function(color1, color2) { - var readability = tinycolor.readability(color1, color2); - return readability.brightness > 125 && readability.color > 500; - }; - - // `mostReadable` - // Given a base color and a list of possible foreground or background - // colors for that base, returns the most readable color. - // *Example* - // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" - tinycolor.mostReadable = function(baseColor, colorList) { - var bestColor = null; - var bestScore = 0; - var bestIsReadable = false; - for (var i=0; i < colorList.length; i++) { - - // We normalize both around the "acceptable" breaking point, - // but rank brightness constrast higher than hue. - - var readability = tinycolor.readability(baseColor, colorList[i]); - var readable = readability.brightness > 125 && readability.color > 500; - var score = 3 * (readability.brightness / 125) + (readability.color / 500); - - if ((readable && ! bestIsReadable) || - (readable && bestIsReadable && score > bestScore) || - ((! readable) && (! bestIsReadable) && score > bestScore)) { - bestIsReadable = readable; - bestScore = score; - bestColor = tinycolor(colorList[i]); - } - } - return bestColor; - }; - - - // Big List of Colors - // ------------------ - // - var names = tinycolor.names = { - aliceblue: "f0f8ff", - antiquewhite: "faebd7", - aqua: "0ff", - aquamarine: "7fffd4", - azure: "f0ffff", - beige: "f5f5dc", - bisque: "ffe4c4", - black: "000", - blanchedalmond: "ffebcd", - blue: "00f", - blueviolet: "8a2be2", - brown: "a52a2a", - burlywood: "deb887", - burntsienna: "ea7e5d", - cadetblue: "5f9ea0", - chartreuse: "7fff00", - chocolate: "d2691e", - coral: "ff7f50", - cornflowerblue: "6495ed", - cornsilk: "fff8dc", - crimson: "dc143c", - cyan: "0ff", - darkblue: "00008b", - darkcyan: "008b8b", - darkgoldenrod: "b8860b", - darkgray: "a9a9a9", - darkgreen: "006400", - darkgrey: "a9a9a9", - darkkhaki: "bdb76b", - darkmagenta: "8b008b", - darkolivegreen: "556b2f", - darkorange: "ff8c00", - darkorchid: "9932cc", - darkred: "8b0000", - darksalmon: "e9967a", - darkseagreen: "8fbc8f", - darkslateblue: "483d8b", - darkslategray: "2f4f4f", - darkslategrey: "2f4f4f", - darkturquoise: "00ced1", - darkviolet: "9400d3", - deeppink: "ff1493", - deepskyblue: "00bfff", - dimgray: "696969", - dimgrey: "696969", - dodgerblue: "1e90ff", - firebrick: "b22222", - floralwhite: "fffaf0", - forestgreen: "228b22", - fuchsia: "f0f", - gainsboro: "dcdcdc", - ghostwhite: "f8f8ff", - gold: "ffd700", - goldenrod: "daa520", - gray: "808080", - green: "008000", - greenyellow: "adff2f", - grey: "808080", - honeydew: "f0fff0", - hotpink: "ff69b4", - indianred: "cd5c5c", - indigo: "4b0082", - ivory: "fffff0", - khaki: "f0e68c", - lavender: "e6e6fa", - lavenderblush: "fff0f5", - lawngreen: "7cfc00", - lemonchiffon: "fffacd", - lightblue: "add8e6", - lightcoral: "f08080", - lightcyan: "e0ffff", - lightgoldenrodyellow: "fafad2", - lightgray: "d3d3d3", - lightgreen: "90ee90", - lightgrey: "d3d3d3", - lightpink: "ffb6c1", - lightsalmon: "ffa07a", - lightseagreen: "20b2aa", - lightskyblue: "87cefa", - lightslategray: "789", - lightslategrey: "789", - lightsteelblue: "b0c4de", - lightyellow: "ffffe0", - lime: "0f0", - limegreen: "32cd32", - linen: "faf0e6", - magenta: "f0f", - maroon: "800000", - mediumaquamarine: "66cdaa", - mediumblue: "0000cd", - mediumorchid: "ba55d3", - mediumpurple: "9370db", - mediumseagreen: "3cb371", - mediumslateblue: "7b68ee", - mediumspringgreen: "00fa9a", - mediumturquoise: "48d1cc", - mediumvioletred: "c71585", - midnightblue: "191970", - mintcream: "f5fffa", - mistyrose: "ffe4e1", - moccasin: "ffe4b5", - navajowhite: "ffdead", - navy: "000080", - oldlace: "fdf5e6", - olive: "808000", - olivedrab: "6b8e23", - orange: "ffa500", - orangered: "ff4500", - orchid: "da70d6", - palegoldenrod: "eee8aa", - palegreen: "98fb98", - paleturquoise: "afeeee", - palevioletred: "db7093", - papayawhip: "ffefd5", - peachpuff: "ffdab9", - peru: "cd853f", - pink: "ffc0cb", - plum: "dda0dd", - powderblue: "b0e0e6", - purple: "800080", - red: "f00", - rosybrown: "bc8f8f", - royalblue: "4169e1", - saddlebrown: "8b4513", - salmon: "fa8072", - sandybrown: "f4a460", - seagreen: "2e8b57", - seashell: "fff5ee", - sienna: "a0522d", - silver: "c0c0c0", - skyblue: "87ceeb", - slateblue: "6a5acd", - slategray: "708090", - slategrey: "708090", - snow: "fffafa", - springgreen: "00ff7f", - steelblue: "4682b4", - tan: "d2b48c", - teal: "008080", - thistle: "d8bfd8", - tomato: "ff6347", - turquoise: "40e0d0", - violet: "ee82ee", - wheat: "f5deb3", - white: "fff", - whitesmoke: "f5f5f5", - yellow: "ff0", - yellowgreen: "9acd32" - }; - - // Make it easy to access colors via `hexNames[hex]` - var hexNames = tinycolor.hexNames = flip(names); - - - // Utilities - // --------- - - // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` - function flip(o) { - var flipped = { }; - for (var i in o) { - if (o.hasOwnProperty(i)) { - flipped[o[i]] = i; - } - } - return flipped; - } - - // Return a valid alpha value [0,1] with all invalid values being set to 1 - function boundAlpha(a) { - a = parseFloat(a); - - if (isNaN(a) || a < 0 || a > 1) { - a = 1; - } - - return a; - } - - // Take input from [0, n] and return it as [0, 1] - function bound01(n, max) { - if (isOnePointZero(n)) { n = "100%"; } - - var processPercent = isPercentage(n); - n = mathMin(max, mathMax(0, parseFloat(n))); - - // Automatically convert percentage into number - if (processPercent) { - n = parseInt(n * max, 10) / 100; - } - - // Handle floating point rounding errors - if ((math.abs(n - max) < 0.000001)) { - return 1; - } - - // Convert into [0, 1] range if it isn't already - return (n % max) / parseFloat(max); - } - - // Force a number between 0 and 1 - function clamp01(val) { - return mathMin(1, mathMax(0, val)); - } - - // Parse an integer into hex - function parseHex(val) { - return parseInt(val, 16); - } - - // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 - // - function isOnePointZero(n) { - return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; - } - - // Check to see if string passed in is a percentage - function isPercentage(n) { - return typeof n === "string" && n.indexOf('%') != -1; - } - - // Force a hex value to have 2 characters - function pad2(c) { - return c.length == 1 ? '0' + c : '' + c; - } - - // Replace a decimal with it's percentage value - function convertToPercentage(n) { - if (n <= 1) { - n = (n * 100) + "%"; - } - - return n; - } - - var matchers = (function() { - - // - var CSS_INTEGER = "[-\\+]?\\d+%?"; - - // - var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; - - // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. - var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; - - // Actual matching. - // Parentheses and commas are optional, but not required. - // Whitespace can take the place of commas or opening paren - var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; - - return { - rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), - rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), - hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), - hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), - hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), - hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, - hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ - }; - })(); - - // `stringInputToObject` - // Permissive string parsing. Take in a number of formats, and output an object - // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` - function stringInputToObject(color) { - - color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); - var named = false; - if (names[color]) { - color = names[color]; - named = true; - } - else if (color == 'transparent') { - return { r: 0, g: 0, b: 0, a: 0, format: "name" }; - } - - // Try to match string input using regular expressions. - // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] - // Just return an object and let the conversion functions handle that. - // This way the result will be the same whether the tinycolor is initialized with string or object. - var match; - if ((match = matchers.rgb.exec(color))) { - return { r: match[1], g: match[2], b: match[3] }; - } - if ((match = matchers.rgba.exec(color))) { - return { r: match[1], g: match[2], b: match[3], a: match[4] }; - } - if ((match = matchers.hsl.exec(color))) { - return { h: match[1], s: match[2], l: match[3] }; - } - if ((match = matchers.hsla.exec(color))) { - return { h: match[1], s: match[2], l: match[3], a: match[4] }; - } - if ((match = matchers.hsv.exec(color))) { - return { h: match[1], s: match[2], v: match[3] }; - } - if ((match = matchers.hex6.exec(color))) { - return { - r: parseHex(match[1]), - g: parseHex(match[2]), - b: parseHex(match[3]), - format: named ? "name" : "hex" - }; - } - if ((match = matchers.hex3.exec(color))) { - return { - r: parseHex(match[1] + '' + match[1]), - g: parseHex(match[2] + '' + match[2]), - b: parseHex(match[3] + '' + match[3]), - format: named ? "name" : "hex" - }; - } - - return false; - } - - // Expose tinycolor to window, does not need to run in non-browser context. - window.tinycolor = tinycolor; - - })(); - var tinycolor = window.tinycolor; - - $(function () { - if ($.fn.spectrum.load) { - $.fn.spectrum.processNativeColorInputs(); - } - }); - -})(window, jQuery); -;(function () { - var ns = $.namespace("pskl.rendering"); - - ns.DrawingLoop = function () { - this.requestAnimationFrame = this.getRequestAnimationFrameShim_(); - this.isRunning = false; - this.previousTime = 0; - this.callbacks = []; - }; - - ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { - var callbackObj = { - fn : callback, - scope : scope, - args : args - }; - this.callbacks.push(callbackObj); - return callbackObj; - }; - - ns.DrawingLoop.prototype.removeCallback = function (callbackObj) { - var index = this.callbacks.indexOf(callbackObj); - if (index != -1) { - this.callbacks.splice(index, 1); - } - }; - - ns.DrawingLoop.prototype.start = function () { - this.isRunning = true; - this.loop_(); - }; - - ns.DrawingLoop.prototype.loop_ = function () { - var currentTime = Date.now(); - var delta = currentTime - this.previousTime; - this.executeCallbacks_(delta); - this.previousTime = currentTime; - this.requestAnimationFrame.call(window, this.loop_.bind(this)); - }; - - ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { - for (var i = 0 ; i < this.callbacks.length ; i++) { - var cb = this.callbacks[i]; - cb.fn.call(cb.scope, deltaTime, cb.args); - } - }; - - ns.DrawingLoop.prototype.stop = function () { - this.isRunning = false; - }; - - ns.DrawingLoop.prototype.getRequestAnimationFrameShim_ = function () { - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { window.setTimeout(callback, 1000/60); }; - - return requestAnimationFrame; - }; -})();;(function () { - var ns = $.namespace("pskl.model"); - var __idCounter = 0; - ns.Frame = function (width, height) { - if (width && height) { - this.width = width; - this.height = height; - this.id = __idCounter++; - this.version = 0; - this.pixels = ns.Frame.createEmptyPixelGrid_(width, height); - this.stateIndex = 0; - } else { - throw 'Bad arguments in pskl.model.Frame constructor : ' + width + ', ' + height; - } - }; - - ns.Frame.fromPixelGrid = function (pixels) { - if (pixels.length && pixels[0].length) { - var w = pixels.length, h = pixels[0].length; - var frame = new pskl.model.Frame(w, h); - frame.setPixels(pixels); - return frame; - } else { - throw 'Bad arguments in pskl.model.Frame.fromPixelGrid : ' + pixels; - } - }; - - ns.Frame.createEmptyPixelGrid_ = function (width, height) { - var pixels = []; //new Array(width); - for (var columnIndex=0; columnIndex < width; columnIndex++) { - var columnArray = []; - for(var heightIndex = 0; heightIndex < height; heightIndex++) { - columnArray.push(Constants.TRANSPARENT_COLOR); - } - pixels[columnIndex] = columnArray; - } - return pixels; - }; - - ns.Frame.createEmptyFromFrame = function (frame) { - return new ns.Frame(frame.getWidth(), frame.getHeight()); - }; - - ns.Frame.prototype.clone = function () { - var clone = new ns.Frame(this.width, this.height); - clone.setPixels(this.getPixels()); - return clone; - }; - - /** - * Returns a copy of the pixels used by the frame - */ - ns.Frame.prototype.getPixels = function () { - return this.clonePixels_(this.pixels); - }; - - /** - * Copies the passed pixels into the frame. - */ - ns.Frame.prototype.setPixels = function (pixels) { - this.pixels = this.clonePixels_(pixels); - this.version++; - }; - - ns.Frame.prototype.clear = function () { - var pixels = ns.Frame.createEmptyPixelGrid_(this.getWidth(), this.getHeight()); - this.setPixels(pixels); - }; - - /** - * Clone a set of pixels. Should be static utility method - * @private - */ - ns.Frame.prototype.clonePixels_ = function (pixels) { - var clonedPixels = []; - for (var col = 0 ; col < pixels.length ; col++) { - clonedPixels[col] = pixels[col].slice(0 , pixels[col].length); - } - return clonedPixels; - }; - - ns.Frame.prototype.getHash = function () { - return [this.id, this.version].join('-'); - }; - - ns.Frame.prototype.setPixel = function (x, y, color) { - if (this.containsPixel(x, y)) { - var p = this.pixels[x][y]; - if (p !== color) { - this.pixels[x][y] = color; - this.version++; - } - } - }; - - ns.Frame.prototype.getPixel = function (x, y) { - if (this.containsPixel(x, y)) { - return this.pixels[x][y]; - } else { - return null; - } - }; - - ns.Frame.prototype.forEachPixel = function (callback) { - var width = this.getWidth(); - var height = this.getHeight(); - for (var x = 0 ; x < width ; x++) { - for (var y = 0 ; y < height ; y++) { - callback(this.pixels[x][y], x, y, this); - } - } - }; - - ns.Frame.prototype.getWidth = function () { - return this.width; - }; - - ns.Frame.prototype.getHeight = function () { - return this.height; - }; - - ns.Frame.prototype.containsPixel = function (col, row) { - return col >= 0 && row >= 0 && col < this.width && row < this.height; - }; - - ns.Frame.prototype.isSameSize = function (otherFrame) { - return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth(); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Layer = function (name) { - if (!name) { - throw 'Invalid arguments in Layer constructor : \'name\' is mandatory'; - } else { - this.name = name; - this.frames = []; - } - }; - - /** - * Create a Layer instance from an already existing set a Frames - * @static - * @param {String} name layer's name - * @param {Array} frames should all have the same dimensions - * @return {pskl.model.Layer} - */ - ns.Layer.fromFrames = function (name, frames) { - var layer = new ns.Layer(name); - frames.forEach(layer.addFrame.bind(layer)); - return layer; - }; - - ns.Layer.prototype.getName = function () { - return this.name; - }; - - ns.Layer.prototype.setName = function (name) { - this.name = name; - }; - - ns.Layer.prototype.getFrames = function () { - return this.frames; - }; - - ns.Layer.prototype.getFrameAt = function (index) { - return this.frames[index]; - }; - - ns.Layer.prototype.addFrame = function (frame) { - this.frames.push(frame); - }; - - ns.Layer.prototype.addFrameAt = function (frame, index) { - this.frames.splice(index, 0, frame); - }; - - ns.Layer.prototype.removeFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.removeFrameAt(index); - }; - - ns.Layer.prototype.removeFrameAt = function (index) { - if (this.frames[index]) { - this.frames.splice(index, 1); - } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.length() + ')'; - } - }; - - ns.Layer.prototype.moveFrame = function (fromIndex, toIndex) { - var frame = this.frames.splice(fromIndex, 1)[0]; - this.frames.splice(toIndex, 0, frame); - }; - - ns.Layer.prototype.swapFramesAt = function (fromIndex, toIndex) { - var fromFrame = this.frames[fromIndex]; - var toFrame = this.frames[toIndex]; - if (fromFrame && toFrame) { - this.frames[toIndex] = fromFrame; - this.frames[fromIndex] = toFrame; - } else { - console.log('frames', this.frames); - console.log('fromIndex', fromIndex, 'toIndex', toIndex); - throw 'Frame not found in moveFrameAt'; - } - }; - - ns.Layer.prototype.duplicateFrame = function (frame) { - var index = this.frames.indexOf(frame); - this.duplicateFrameAt(index); - }; - - ns.Layer.prototype.duplicateFrameAt = function (index) { - var frame = this.frames[index]; - if (frame) { - var clone = frame.clone(); - this.addFrameAt(clone, index); - } else { - throw 'Frame not found in duplicateFrameAt'; - } - }; - - ns.Layer.prototype.length = function () { - return this.frames.length; - }; - - ns.Layer.prototype.getHash = function () { - return this.frames.map(function (frame) { - return frame.getHash(); - }).join('-'); - }; -})();;(function () { - var ns = $.namespace('pskl.model.piskel'); - - ns.Descriptor = function (name, description, isPublic) { - this.name = name; - this.description = description; - this.isPublic = isPublic; - }; -})();;(function () { - var ns = $.namespace('pskl.model.frame'); - - - var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; - - var DEFAULT_FRAME_PROCESSOR = function (frame) { - return pskl.utils.FrameUtils.toImage(frame); - }; - - var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; - - var DEFAULT_NAMESPACE = '__cache_default__'; - - ns.CachedFrameProcessor = function (cacheResetInterval) { - this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; - this.frameProcessor = DEFAULT_FRAME_PROCESSOR; - this.outputCloner = DEFAULT_OUTPUT_CLONER; - - window.setInterval(this.clear.bind(this), this.cacheResetInterval); - }; - - ns.CachedFrameProcessor.prototype.clear = function () { - this.cache_ = {}; - }; - - /** - * Set the processor function that will be called when there is a cache miss - * Function with 1 argument : pskl.model.Frame - * @param {Function} frameProcessor - */ - ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { - this.frameProcessor = frameProcessor; - }; - - /** - * Set the cloner that will be called when there is a miss on the 1st level cache - * but a hit on the 2nd level cache. - * Function with 2 arguments : cached value, frame - * @param {Function} outputCloner - */ - ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { - this.outputCloner = outputCloner; - }; - - /** - * Retrieve the processed frame from the cache, in the (optional) namespace - * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. - * @param {pskl.model.Frame} frame - * @param {String} namespace - * @return {Object} the processed frame - */ - ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { - var processedFrame = null; - namespace = namespace || DEFAULT_NAMESPACE; - - if (!this.cache_[namespace]) { - this.cache_[namespace] = {}; - } - - var cache = this.cache_[namespace]; - - var cacheKey = frame.getHash(); - if (cache[cacheKey]) { - processedFrame = cache[cacheKey]; - } else { - var frameAsString = JSON.stringify(frame.getPixels()); - if (cache[frameAsString]) { - processedFrame = this.outputCloner(cache[frameAsString], frame); - } else { - processedFrame = this.frameProcessor(frame); - cache[frameAsString] = processedFrame; - } - cache[cacheKey] = processedFrame; - } - return processedFrame; - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - ns.Palette = function (id, name, colors) { - this.id = id; - this.name = name; - this.colors = colors; - }; - - ns.Palette.fromObject = function (paletteObj) { - var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); - return new ns.Palette(paletteObj.id, paletteObj.name, colors); - }; - - ns.Palette.prototype.get = function (index) { - return this.colors[index]; - }; - - ns.Palette.prototype.set = function (index, color) { - this.colors[index] = color; - }; - - ns.Palette.prototype.add = function (color) { - this.colors.push(color); - }; - - ns.Palette.prototype.size = function () { - return this.colors.length; - }; - - ns.Palette.prototype.removeAt = function (index) { - this.colors.splice(index, 1); - }; - - ns.Palette.prototype.move = function (oldIndex, newIndex) { - this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); - }; -})();;(function () { - var ns = $.namespace('pskl.model'); - - /** - * @constructor - * @param {Number} width - * @param {Number} height - * @param {String} name - * @param {String} description - */ - ns.Piskel = function (width, height, descriptor) { - if (width && height && descriptor) { - /** @type {Array} */ - this.layers = []; - - /** @type {Number} */ - this.width = width; - - /** @type {Number} */ - this.height = height; - - this.descriptor = descriptor; - } else { - throw 'Missing arguments in Piskel constructor : ' + Array.prototype.join.call(arguments, ","); - } - }; - - /** - * Create a piskel instance from an existing set of (non empty) layers - * Layers should all be synchronized : same number of frames, same dimensions - * @param {Array} layers - * @return {pskl.model.Piskel} - */ - ns.Piskel.fromLayers = function (layers, descriptor) { - var piskel = null; - if (layers.length > 0 && layers[0].length() > 0) { - var sampleFrame = layers[0].getFrameAt(0); - piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); - layers.forEach(piskel.addLayer.bind(piskel)); - } else { - throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; - } - return piskel; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getHeight = function () { - return this.height; - }; - - ns.Piskel.prototype.getWidth = function () { - return this.width; - }; - - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; - - ns.Piskel.prototype.getLayerAt = function (index) { - return this.layers[index]; - }; - - ns.Piskel.prototype.getLayersByName = function (name) { - return this.layers.filter(function (l) { - return l.getName() == name; - }); - }; - - ns.Piskel.prototype.addLayer = function (layer) { - this.layers.push(layer); - }; - - ns.Piskel.prototype.moveLayerUp = function (layer) { - var index = this.layers.indexOf(layer); - if (index > -1 && index < this.layers.length-1) { - this.layers[index] = this.layers[index+1]; - this.layers[index+1] = layer; - } - }; - - ns.Piskel.prototype.moveLayerDown = function (layer) { - var index = this.layers.indexOf(layer); - if (index > 0) { - this.layers[index] = this.layers[index-1]; - this.layers[index-1] = layer; - } - }; - - ns.Piskel.prototype.removeLayer = function (layer) { - var index = this.layers.indexOf(layer); - if (index != -1) { - this.layers.splice(index, 1); - } - }; - - ns.Piskel.prototype.removeLayerAt = function (index) { - this.layers.splice(index, 1); - }; - - ns.Piskel.prototype.getDescriptor = function () { - return this.descriptor; - }; - - ns.Piskel.prototype.setDescriptor = function (descriptor) { - this.descriptor = descriptor; - var appEngineEditorHeader = $('.piskel-name').html(this.descriptor.name); - }; - - ns.Piskel.prototype.getHash = function () { - return this.layers.map(function (layer) { - return layer.getHash(); - }).join('-'); - }; - -})();;(function () { - var ns = $.namespace("pskl.selection"); - - var SELECTION_REPLAY = { - PASTE : 'REPLAY_PASTE', - ERASE : 'REPLAY_ERASE' - }; - - ns.SelectionManager = function (piskelController) { - - this.piskelController = piskelController; - - this.currentSelection = null; - }; - - ns.SelectionManager.prototype.init = function () { - $.subscribe(Events.SELECTION_CREATED, $.proxy(this.onSelectionCreated_, this)); - $.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this)); - $.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this)); - - pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this)); - pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this)); - pskl.app.shortcutService.addShortcut('del', this.erase.bind(this)); - pskl.app.shortcutService.addShortcut('back', this.onBackPressed_.bind(this)); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this)); - }; - - /** - * @private - */ - ns.SelectionManager.prototype.cleanSelection_ = function() { - if(this.currentSelection) { - this.currentSelection.reset(); - this.currentSelection = null; - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) { - var isSelectionTool = tool instanceof pskl.drawingtools.BaseSelect; - if(!isSelectionTool) { - this.cleanSelection_(); - } - }; - - /** - * @private - */ - ns.SelectionManager.prototype.onSelectionDismissed_ = function(evt) { - this.cleanSelection_(); - }; - - ns.SelectionManager.prototype.onBackPressed_ = function(evt) { - if (this.currentSelection) { - this.erase(); - } else { - return true; // bubble - } - }; - - ns.SelectionManager.prototype.erase = function () { - var pixels = this.currentSelection.pixels; - var currentFrame = this.piskelController.getCurrentFrame(); - for(var i=0, l=pixels.length; i 0) { - return this.renderers[0]; - } else { - throw 'Renderer manager is empty'; - } - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.layer'); - - ns.LayersRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.belowRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.aboveRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); - - this.add(this.belowRenderer); - this.add(this.aboveRenderer); - - this.serializedRendering = ''; - - $.subscribe(Events.PISKEL_RESET, this.flush.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.layer.LayersRenderer, pskl.rendering.CompositeRenderer); - - ns.LayersRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - var currentLayerIndex = this.piskelController.getCurrentLayerIndex(); - - var downLayers = layers.slice(0, currentLayerIndex); - var upLayers = layers.slice(currentLayerIndex + 1, layers.length); - - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - this.getHashForLayersAt_(currentFrameIndex, downLayers), - this.getHashForLayersAt_(currentFrameIndex, upLayers), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - this.clear(); - - if (downLayers.length > 0) { - var downFrame = this.getFrameForLayersAt_(currentFrameIndex, downLayers); - this.belowRenderer.render(downFrame); - } - - if (upLayers.length > 0) { - var upFrame = this.getFrameForLayersAt_(currentFrameIndex, upLayers); - this.aboveRenderer.render(upFrame); - } - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.LayersRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.LayersRenderer.prototype.getFrameForLayersAt_ = function (frameIndex, layers) { - var frames = layers.map(function (l) { - return l.getFrameAt(frameIndex); - }); - return pskl.utils.FrameUtils.merge(frames); - }; - - ns.LayersRenderer.prototype.getHashForLayersAt_ = function (frameIndex, layers) { - var hash = layers.map(function (l) { - return l.getFrameAt(frameIndex).getHash(); - }); - return hash.join('-'); - }; - - ns.LayersRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})(); -;(function () { - var ns = $.namespace("pskl.rendering.frame"); - - /** - * FrameRenderer will display a given frame inside a canvas element. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classes array of strings to use for css classes - */ - ns.FrameRenderer = function (container, renderingOptions, classes) { - this.defaultRenderingOptions = { - 'supportGridRendering' : false, - 'zoom' : 1 - }; - - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - - if(container === undefined) { - throw 'Bad FrameRenderer initialization. undefined.'; - } - - if(isNaN(renderingOptions.zoom)) { - throw 'Bad FrameRenderer initialization. not well defined.'; - } - - this.container = container; - - this.zoom = renderingOptions.zoom; - - this.offset = { - x : 0, - y : 0 - }; - - this.margin = { - x : 0, - y : 0 - }; - - this.supportGridRendering = renderingOptions.supportGridRendering; - - this.classes = classes || []; - this.classes.push('canvas'); - - /** - * Off dom canvas, will be used to draw the frame at 1:1 ratio - * @type {HTMLElement} - */ - this.canvas = null; - - /** - * Displayed canvas, scaled-up from the offdom canvas - * @type {HTMLElement} - */ - this.displayCanvas = null; - this.setDisplaySize(renderingOptions.width, renderingOptions.height); - - this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - }; - - pskl.utils.inherit(pskl.rendering.frame.FrameRenderer, pskl.rendering.AbstractRenderer); - - ns.FrameRenderer.prototype.render = function (frame) { - if (frame) { - this.clear(); - this.renderFrame_(frame); - } - }; - - ns.FrameRenderer.prototype.clear = function () { - pskl.CanvasUtils.clear(this.canvas); - pskl.CanvasUtils.clear(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth/(2*this.zoom)); - var centerY = this.offset.y + (this.displayHeight/(2*this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth/(2*this.zoom)), - centerY - (this.displayHeight/(2*this.zoom)) - ); - } - }; - - ns.FrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayWidth = width; - this.displayHeight = height; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - this.createDisplayCanvas_(); - }; - - ns.FrameRenderer.prototype.getDisplaySize = function () { - return { - height : this.displayHeight, - width : this.displayWidth - }; - }; - - ns.FrameRenderer.prototype.getOffset = function () { - return { - x : this.offset.x, - y : this.offset.y - }; - }; - - ns.FrameRenderer.prototype.setOffset = function (x, y) { - var width = pskl.app.piskelController.getWidth(); - var height = pskl.app.piskelController.getHeight(); - var maxX = width - (this.displayWidth/this.zoom); - x = pskl.utils.Math.minmax(x, 0, maxX); - var maxY = height - (this.displayHeight/this.zoom); - y = pskl.utils.Math.minmax(y, 0, maxY); - - this.offset.x = x; - this.offset.y = y; - }; - - ns.FrameRenderer.prototype.setGridWidth = function (value) { - this.gridWidth_ = value; - }; - - ns.FrameRenderer.prototype.getGridWidth = function () { - if (this.supportGridRendering) { - return this.gridWidth_; - } else { - return 0; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function (frame) { - var deltaX = this.displayWidth - (this.zoom * frame.getWidth()); - this.margin.x = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * frame.getHeight()); - this.margin.y = Math.max(0, deltaY) / 2; - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - this.displayCanvas = pskl.CanvasUtils.createCanvas(width, height, this.classes); - pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas); - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.GRID_WIDTH) { - this.setGridWidth(settingValue); - } - }; - - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - - // apply margins - x = x - this.margin.x; - y = y - this.margin.y; - - var cellSize = this.zoom; - // apply frame offset - x = x + this.offset.x * cellSize; - y = y + this.offset.y * cellSize; - - return { - x : Math.floor(x / cellSize), - y : Math.floor(y / cellSize) - }; - }; - - ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) { - var cellSize = this.zoom; - - x = x * cellSize; - y = y * cellSize; - - x = x - this.offset.x * cellSize; - y = y - this.offset.y * cellSize; - - x = x + this.margin.x; - y = y + this.margin.y; - - var containerOffset = this.container.offset(); - x = x + containerOffset.left; - y = y + containerOffset.top; - - return { - x : x + (cellSize/2), - y : y + (cellSize/2) - }; - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.renderFrame_ = function (frame) { - if (!this.canvas || frame.getWidth() != this.canvas.width || frame.getHeight() != this.canvas.height) { - this.canvas = pskl.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); - } - - var context = this.canvas.getContext('2d'); - for(var x = 0, width = frame.getWidth(); x < width; x++) { - for(var y = 0, height = frame.getHeight(); y < height; y++) { - var color = frame.getPixel(x, y); - this.renderPixel_(color, x, y, context); - } - } - - this.updateMargins_(frame); - - var displayContext = this.displayCanvas.getContext('2d'); - displayContext.save(); - - if (this.canvas.width*this.zoom < this.displayCanvas.width) { - displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR; - displayContext.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - } - - displayContext.translate( - this.margin.x-this.offset.x*this.zoom, - this.margin.y-this.offset.y*this.zoom - ); - - displayContext.clearRect(0, 0, this.canvas.width*this.zoom, this.canvas.height*this.zoom); - - var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; - - var gridWidth = this.getGridWidth(); - var isGridEnabled = gridWidth > 0; - if (isGridEnabled || isIE10) { - var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth); - displayContext.drawImage(scaled, 0, 0); - } else { - displayContext.scale(this.zoom, this.zoom); - displayContext.drawImage(this.canvas, 0, 0); - } - displayContext.restore(); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - ns.OnionSkinRenderer = function (container, renderingOptions, piskelController) { - pskl.rendering.CompositeRenderer.call(this); - - this.piskelController = piskelController; - - // Do not use CachedFrameRenderers here, since the caching will be performed in the render method of LayersRenderer - this.renderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, ["onion-skin-canvas"]); - - this.add(this.renderer); - - this.serializedRendering = ''; - }; - - pskl.utils.inherit(pskl.rendering.OnionSkinRenderer, pskl.rendering.CompositeRenderer); - - ns.OnionSkinRenderer.prototype.render = function () { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var layers = this.piskelController.getLayers(); - var currentFrameIndex = this.piskelController.getCurrentFrameIndex(); - - var frames = []; - this.addFrameAtIndexToArray_(currentFrameIndex - 1, frames); - this.addFrameAtIndexToArray_(currentFrameIndex + 1, frames); - - var serializedRendering = [ - this.getZoom(), - this.getGridWidth(), - offset.x, - offset.y, - size.width, - size.height, - frames.map(function (f) { - return f.getHash(); - }).join('-'), - layers.length - ].join("-"); - - - if (this.serializedRendering != serializedRendering) { - this.serializedRendering = serializedRendering; - - if (frames.length > 0) { - this.clear(); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - this.renderer.render(mergedFrame); - } - } - }; - - ns.OnionSkinRenderer.prototype.addFrameAtIndexToArray_ = function (frameIndex, frames) { - var layer = this.piskelController.getCurrentLayer(); - if (this.piskelController.hasFrameAt(frameIndex)) { - frames.push(layer.getFrameAt(frameIndex)); - } - }; - - /** - * See @pskl.rendering.frame.CachedFrameRenderer - * Same issue : FrameRenderer setDisplaySize destroys the canvas - * @param {Number} width - * @param {Number} height - */ - ns.OnionSkinRenderer.prototype.setDisplaySize = function (width, height) { - var size = this.getDisplaySize(); - if (size.width !== width || size.height !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.OnionSkinRenderer.prototype.flush = function () { - this.serializedRendering = ''; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - this.displayContainer = document.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})();;(function () { - var ns = $.namespace('pskl.rendering.frame'); - - /** - * FrameRenderer implementation that prevents unnecessary redraws. - * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame - * @param {Object} renderingOptions - * @param {Array} classes array of strings to use for css classes - */ - ns.CachedFrameRenderer = function (container, renderingOptions, classes) { - pskl.rendering.frame.FrameRenderer.call(this, container, renderingOptions, classes); - this.serializedFrame = ''; - }; - - pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.frame.FrameRenderer); - - /** - * Only call display size if provided values are different from current values. - * FrameRenderer:setDisplaySize destroys the underlying canvas - * If the canvas is destroyed, a rendering is mandatory. - * (Alternatively we could find a way to force the rendering of the CachedFrameRenderer from the outside) - * @param {Number} width - * @param {Number} height - */ - ns.CachedFrameRenderer.prototype.setDisplaySize = function (width, height) { - if (this.displayWidth !== width || this.displayHeight !== height) { - this.superclass.setDisplaySize.call(this, width, height); - } - }; - - ns.CachedFrameRenderer.prototype.render = function (frame) { - var offset = this.getOffset(); - var size = this.getDisplaySize(); - var serializedFrame = [ - this.getZoom(), - this.getGridWidth(), - offset.x, offset.y, - size.width, size.height, - frame.getHash() - ].join('-'); - if (this.serializedFrame != serializedFrame) { - // console.log('rendering') - this.serializedFrame = serializedFrame; - this.superclass.render.call(this, frame); - } - }; -})(); -;(function () { - - var ns = $.namespace("pskl.rendering"); - ns.CanvasRenderer = function (frame, zoom) { - this.frame = frame; - this.zoom = zoom; - this.transparentColor_ = 'white'; - }; - - /** - * Decide which color should be used to represent transparent pixels - * Default : white - * @param {String} color the color to use either as '#ABCDEF' or 'red' or 'rgb(x,y,z)' or 'rgba(x,y,z,a)' - */ - ns.CanvasRenderer.prototype.drawTransparentAs = function (color) { - this.transparentColor_ = color; - }; - - ns.CanvasRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - var context = canvas.getContext('2d'); - this.frame.forEachPixel(function (color, x, y) { - this.renderPixel_(color, x, y, context); - }.bind(this)); - - var scaledCanvas = this.createCanvas_(this.zoom); - var scaledContext = scaledCanvas.getContext('2d'); - pskl.CanvasUtils.disableImageSmoothing(scaledCanvas); - scaledContext.scale(this.zoom, this.zoom); - scaledContext.drawImage(canvas, 0, 0); - - return scaledCanvas; - }; - - ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color == Constants.TRANSPARENT_COLOR) { - color = this.transparentColor_; - } - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - }; - - ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { - zoom = zoom || 1; - var width = this.frame.getWidth() * zoom; - var height = this.frame.getHeight() * zoom; - return pskl.CanvasUtils.createCanvas(width, height); - }; -})();;(function () { - var ns = $.namespace('pskl.rendering'); - - /** - * Render an array of frames - * @param {Array.} frames - */ - ns.FramesheetRenderer = function (frames) { - if (frames.length > 0) { - this.frames = frames; - } else { - throw 'FramesheetRenderer : Invalid argument : frames is empty'; - } - }; - - ns.FramesheetRenderer.prototype.renderAsCanvas = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.frames.length ; i++) { - var frame = this.frames[i]; - this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); - } - return canvas; - }; - - ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - frame.forEachPixel(function (color, x, y) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); - } - }); - }; - - ns.FramesheetRenderer.prototype.createCanvas_ = function () { - var sampleFrame = this.frames[0]; - var count = this.frames.length; - var width = count * sampleFrame.getWidth(); - var height = sampleFrame.getHeight(); - return pskl.CanvasUtils.createCanvas(width, height); - }; - -})();;(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.PiskelRenderer = function (piskelController) { - var frames = []; - for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { - frames.push(piskelController.getFrameAt(i)); - } - ns.FramesheetRenderer.call(this, frames); - }; - - pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PiskelController = function (piskel) { - if (piskel) { - this.setPiskel(piskel); - } else { - throw 'A piskel instance is mandatory for instanciating PiskelController'; - } - }; - - /** - * Set the current piskel. Will reset the selected frame and layer unless specified - * @param {Object} piskel - * @param {Boolean} preserveState if true, keep the selected frame and layer - */ - ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskel = piskel; - if (!preserveState) { - this.currentLayerIndex = 0; - this.currentFrameIndex = 0; - } - - this.layerIdCounter = 1; - }; - - ns.PiskelController.prototype.init = function () { - }; - - ns.PiskelController.prototype.getHeight = function () { - return this.piskel.getHeight(); - }; - - ns.PiskelController.prototype.getWidth = function () { - return this.piskel.getWidth(); - }; - - /** - * TODO : this should be removed - * FPS should be stored in the Piskel model and not in the - * animationController - * Then piskelController should be able to return this information - * @return {Number} Frames per second for the current animation - */ - ns.PiskelController.prototype.getFPS = function () { - return pskl.app.animationController.getFPS(); - }; - - ns.PiskelController.prototype.getLayers = function () { - return this.piskel.getLayers(); - }; - - ns.PiskelController.prototype.getCurrentLayer = function () { - return this.getLayerAt(this.currentLayerIndex); - }; - - ns.PiskelController.prototype.getLayerAt = function (index) { - return this.piskel.getLayerAt(index); - }; - - ns.PiskelController.prototype.hasLayerAt = function (index) { - return !!this.getLayerAt(index); - }; - - // FIXME ?? No added value compared to getLayerAt ?? - // Except normalizing to null if undefined ?? ==> To merge - ns.PiskelController.prototype.getLayerByIndex = function (index) { - var layers = this.getLayers(); - if (layers[index]) { - return layers[index]; - } else { - return null; - } - }; - - ns.PiskelController.prototype.getCurrentFrame = function () { - var layer = this.getCurrentLayer(); - return layer.getFrameAt(this.currentFrameIndex); - }; - - - ns.PiskelController.prototype.getCurrentLayerIndex = function () { - return this.currentLayerIndex; - }; - - ns.PiskelController.prototype.getCurrentFrameIndex = function () { - return this.currentFrameIndex; - }; - - ns.PiskelController.prototype.getPiskel = function () { - return this.piskel; - }; - - ns.PiskelController.prototype.getFrameAt = function (index) { - var hash = []; - var frames = this.getLayers().map(function (l) { - var frame = l.getFrameAt(index); - hash.push(frame.getHash()); - return frame; - }); - var mergedFrame = pskl.utils.FrameUtils.merge(frames); - mergedFrame.id = hash.join('-'); - mergedFrame.version = 0; - return mergedFrame; - }; - - ns.PiskelController.prototype.hasFrameAt = function (index) { - return !!this.getCurrentLayer().getFrameAt(index); - }; - - ns.PiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.currentFrameIndex + 1); - }; - - ns.PiskelController.prototype.addFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.addFrameAt(this.createEmptyFrame_(), index); - }.bind(this)); - - this.setCurrentFrameIndex(index); - }; - - ns.PiskelController.prototype.createEmptyFrame_ = function () { - var w = this.piskel.getWidth(), h = this.piskel.getHeight(); - return new pskl.model.Frame(w, h); - }; - - ns.PiskelController.prototype.removeFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.removeFrameAt(index); - }); - // Current frame index is impacted if the removed frame was before the current frame - if (this.currentFrameIndex >= index && this.currentFrameIndex > 0) { - this.setCurrentFrameIndex(this.currentFrameIndex - 1); - } - }; - - ns.PiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.currentFrameIndex); - }; - - ns.PiskelController.prototype.duplicateFrameAt = function (index) { - this.getLayers().forEach(function (l) { - l.duplicateFrameAt(index); - }); - this.setCurrentFrameIndex(index+1); - }; - - ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.getLayers().forEach(function (l) { - l.moveFrame(fromIndex, toIndex); - }); - }; - - ns.PiskelController.prototype.getFrameCount = function () { - var layer = this.piskel.getLayerAt(0); - return layer.length(); - }; - - ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { - if (this.hasFrameAt(index)) { - this.currentFrameIndex = index; - } else { - window.console.error('Could not set current frame index to ' + index); - } - }; - - ns.PiskelController.prototype.selectNextFrame = function () { - var nextIndex = this.currentFrameIndex + 1; - if (nextIndex < this.getFrameCount()) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.selectPreviousFrame = function () { - var nextIndex = this.currentFrameIndex - 1; - if (nextIndex >= 0) { - this.setCurrentFrameIndex(nextIndex); - } - }; - - ns.PiskelController.prototype.setCurrentLayerIndex = function (index) { - if (this.hasLayerAt(index)) { - this.currentLayerIndex = index; - } else { - window.console.error('Could not set current layer index to ' + index); - } - }; - - ns.PiskelController.prototype.selectLayer = function (layer) { - var index = this.getLayers().indexOf(layer); - if (index != -1) { - this.setCurrentLayerIndex(index); - } - }; - - ns.PiskelController.prototype.renameLayerAt = function (index, name) { - var layer = this.getLayerByIndex(index); - if (layer) { - layer.setName(name); - } - }; - - ns.PiskelController.prototype.generateLayerName_ = function () { - var name = "Layer " + this.layerIdCounter; - while (this.hasLayerForName_(name)) { - this.layerIdCounter++; - name = "Layer " + this.layerIdCounter; - } - return name; - }; - - ns.PiskelController.prototype.createLayer = function (name) { - if (!name) { - name = this.generateLayerName_(); - } - if (!this.hasLayerForName_(name)) { - var layer = new pskl.model.Layer(name); - for (var i = 0 ; i < this.getFrameCount() ; i++) { - layer.addFrame(this.createEmptyFrame_()); - } - this.piskel.addLayer(layer); - this.setCurrentLayerIndex(this.piskel.getLayers().length - 1); - - } else { - throw 'Layer name should be unique'; - } - }; - - ns.PiskelController.prototype.hasLayerForName_ = function (name) { - return this.piskel.getLayersByName(name).length > 0; - }; - - ns.PiskelController.prototype.moveLayerUp = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerUp(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.moveLayerDown = function () { - var layer = this.getCurrentLayer(); - this.piskel.moveLayerDown(layer); - this.selectLayer(layer); - }; - - ns.PiskelController.prototype.removeLayerAt = function (index) { - if (this.getLayers().length > 1) { - var layer = this.getLayerAt(index); - if (layer) { - this.piskel.removeLayer(layer); - this.setCurrentLayerIndex(0); - } - } - }; - - ns.PiskelController.prototype.serialize = function (expanded) { - return pskl.utils.Serializer.serializePiskel(this.piskel, expanded); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.piskel'); - - ns.PublicPiskelController = function (piskelController) { - this.piskelController = piskelController; - pskl.utils.wrap(this, this.piskelController); - }; - - ns.PublicPiskelController.prototype.init = function () { - pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this)); - pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this)); - pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this)); - pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this)); - }; - - ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) { - this.piskelController.setPiskel(piskel, preserveState); - - $.publish(Events.FRAME_SIZE_CHANGED); - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.PublicPiskelController.prototype.addFrame = function () { - this.addFrameAt(this.getFrameCount()); - }; - - ns.PublicPiskelController.prototype.addFrameAtCurrentIndex = function () { - this.addFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.addFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.addFrameAt, [index]); - this.piskelController.addFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.removeFrameAt, [index]); - this.piskelController.removeFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.duplicateCurrentFrame = function () { - this.duplicateFrameAt(this.getCurrentFrameIndex()); - }; - - ns.PublicPiskelController.prototype.replay = function (frame, replayData) { - replayData.fn.apply(this.piskelController, replayData.args); - }; - - ns.PublicPiskelController.prototype.duplicateFrameAt = function (index) { - this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt, [index]); - this.piskelController.duplicateFrameAt(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveFrame = function (fromIndex, toIndex) { - this.raiseSaveStateEvent_(this.piskelController.moveFrame, [fromIndex, toIndex]); - this.piskelController.moveFrame(fromIndex, toIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentFrameIndex = function (index) { - this.piskelController.setCurrentFrameIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectNextFrame = function () { - this.piskelController.selectNextFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectPreviousFrame = function () { - this.piskelController.selectPreviousFrame(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.setCurrentLayerIndex = function (index) { - this.piskelController.setCurrentLayerIndex(index); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.selectLayer = function (layer) { - this.piskelController.selectLayer(layer); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.renameLayerAt = function (index, name) { - this.raiseSaveStateEvent_(this.piskelController.renameLayerAt, [index, name]); - this.piskelController.renameLayerAt(index, name); - }; - - ns.PublicPiskelController.prototype.createLayer = function (name) { - this.raiseSaveStateEvent_(this.piskelController.createLayer, [name]); - this.piskelController.createLayer(name); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerUp = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerUp, []); - this.piskelController.moveLayerUp(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.moveLayerDown = function () { - this.raiseSaveStateEvent_(this.piskelController.moveLayerDown, []); - this.piskelController.moveLayerDown(); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.removeCurrentLayer = function () { - var currentLayerIndex = this.getCurrentLayerIndex(); - this.raiseSaveStateEvent_(this.piskelController.removeLayerAt, [currentLayerIndex]); - this.piskelController.removeLayerAt(currentLayerIndex); - $.publish(Events.PISKEL_RESET); - }; - - ns.PublicPiskelController.prototype.getCurrentLayerIndex = function () { - return this.piskelController.getCurrentLayerIndex(); - }; - - ns.PublicPiskelController.prototype.getCurrentFrameIndex = function () { - return this.piskelController.currentFrameIndex; - }; - - ns.PublicPiskelController.prototype.getPiskel = function () { - return this.piskelController.piskel; - }; - - ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT, - scope : this, - replay : { - fn : fn, - args : args - } - }); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CursorCoordinatesController = function (piskelController) { - this.piskelController = piskelController; - this.origin = null; - this.coordinates = {x:-1,y:-1}; - - }; - - ns.CursorCoordinatesController.prototype.init = function () { - this.coordinatesContainer = document.querySelector('.cursor-coordinates'); - - $.subscribe(Events.CURSOR_MOVED, this.onCursorMoved_.bind(this)); - $.subscribe(Events.DRAG_START, this.onDragStart_.bind(this)); - $.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this)); - - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.redraw = function () { - var html = ''; - if (this.origin) { - html += this.origin.x + ':' + this.origin.y + ' to '; - } - - var x = this.coordinates.x; - var y = this.coordinates.y; - var currentFrame = this.piskelController.getCurrentFrame(); - if (currentFrame.containsPixel(x, y)) { - html += x + ':' + y; - if (this.origin) { - var dX = Math.abs(x-this.origin.x) + 1; - var dY = Math.abs(y-this.origin.y) + 1; - html += ' (' + dX + 'x' + dY +')'; - } - } - - this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html; - }; - - ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () { - var w = this.piskelController.getWidth(); - var h = this.piskelController.getHeight(); - return '['+w+'x'+h+'] '; - }; - - ns.CursorCoordinatesController.prototype.onCursorMoved_ = function (event, x, y) { - this.coordinates = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragStart_ = function (event, x, y) { - this.origin = {x:x, y:y}; - this.redraw(); - }; - - ns.CursorCoordinatesController.prototype.onDragEnd_ = function (event, x, y) { - this.origin = null; - this.redraw(); - }; - -})();;(function () { - - var ns = $.namespace("pskl.controller"); - - ns.DrawingController = function (piskelController, paletteController, container) { - /** - * @public - */ - this.piskelController = piskelController; - - this.paletteController = paletteController; - - /** - * @public - */ - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame()); - - /** - * @private - */ - this.container = container; - - // TODO(vincz): Store user prefs in a localstorage string ? - var renderingOptions = { - "zoom": this.calculateZoom_(), - "supportGridRendering" : true, - "height" : this.getContainerHeight_(), - "width" : this.getContainerWidth_(), - "xOffset" : 0, - "yOffset" : 0 - }; - - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.onionSkinRenderer = new pskl.rendering.OnionSkinRenderer(this.container, renderingOptions, piskelController); - this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, renderingOptions, piskelController); - - this.compositeRenderer = new pskl.rendering.CompositeRenderer(); - this.compositeRenderer - .add(this.overlayRenderer) - .add(this.renderer) - .add(this.layersRenderer) - .add(this.onionSkinRenderer); - - // State of drawing controller: - this.isClicked = false; - this.previousMousemoveTime = 0; - this.currentToolBehavior = null; - - // State of clicked button (need to be stateful here, see comment in getCurrentColor_) - this.currentMouseButton_ = Constants.LEFT_BUTTON; - }; - - ns.DrawingController.prototype.init = function () { - this.initMouseBehavior(); - - $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { - this.currentToolBehavior = toolBehavior; - this.overlayFrame.clear(); - }, this)); - - $(window).resize($.proxy(this.startResizeTimer_, this)); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChanged_, this)); - - pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); - pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); - pskl.app.shortcutService.addShortcut('-', this.decreaseZoom_.bind(this, 1)); - - window.setTimeout(this.afterWindowResize_.bind(this), 100); - }; - - ns.DrawingController.prototype.initMouseBehavior = function() { - var body = $('body'); - this.container.mousedown($.proxy(this.onMousedown_, this)); - - if (pskl.utils.UserAgent.isChrome) { - this.container.on('mousewheel', $.proxy(this.onMousewheel_, this)); - } else { - this.container.on('wheel', $.proxy(this.onMousewheel_, this)); - } - - window.addEventListener('mouseup', this.onMouseup_.bind(this)); - window.addEventListener('mousemove', this.onMousemove_.bind(this)); - window.addEventListener('keyup', this.onKeyup_.bind(this)); - - // Deactivate right click: - body.contextmenu(this.onCanvasContextMenu_); - }; - - ns.DrawingController.prototype.startResizeTimer_ = function () { - if (this.resizeTimer) { - window.clearInterval(this.resizeTimer); - } - this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); - }; - - ns.DrawingController.prototype.afterWindowResize_ = function () { - var initialWidth = this.compositeRenderer.getDisplaySize().width; - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth; - var newZoom = ratio * this.compositeRenderer.getZoom(); - this.compositeRenderer.setZoom(newZoom); - - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { - if(settingsName == pskl.UserSettings.SHOW_GRID) { - console.warn('DrawingController:onUserSettingsChange_ not implemented !'); - } else if (settingsName == pskl.UserSettings.ONION_SKIN || settingsName == pskl.UserSettings.LAYER_PREVIEW) { - this.onionSkinRenderer.clear(); - this.onionSkinRenderer.flush(); - this.layersRenderer.clear(); - this.layersRenderer.flush(); - this.render(); - } - }; - - ns.DrawingController.prototype.onFrameSizeChanged_ = function () { - this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); - this.centerColumnWrapperHorizontally_(); - this.compositeRenderer.setZoom(this.calculateZoom_()); - this.compositeRenderer.setOffset(0, 0); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousedown_ = function (event) { - $.publish(Events.MOUSE_EVENT, [event, this]); - var frame = this.piskelController.getCurrentFrame(); - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - - if (event.button === Constants.MIDDLE_BUTTON) { - if (frame.containsPixel(coords.x, coords.y)) { - $.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]); - } - } else { - this.isClicked = true; - this.setCurrentButton(event); - this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - - this.currentToolBehavior.applyToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - frame, - this.overlayFrame, - event - ); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMousemove_ = function (event) { - this._clientX = event.clientX; - this._clientY = event.clientY; - - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - - if ((currentTime - this.previousMousemoveTime) > Constants.MOUSEMOVE_THROTTLING ) { - this.moveTool_(this._clientX, this._clientY, event); - this.previousMousemoveTime = currentTime; - } - }; - - ns.DrawingController.prototype.resetZoom_ = function () { - this.setZoom_(this.calculateZoom_()); - }; - - ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() + step); - }; - - ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) { - var step = (zoomMultiplier || 1) * this.getZoomStep_(); - this.setZoom_(this.renderer.getZoom() - step); - }; - - ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; - }; - - ns.DrawingController.prototype.setZoom_ = function (zoom) { - this.compositeRenderer.setZoom(zoom); - $.publish(Events.ZOOM_CHANGED); - }; - - /** - * @private - */ - ns.DrawingController.prototype.onKeyup_ = function (event) { - this.moveTool_(this._clientX, this._clientY, event); - }; - - ns.DrawingController.prototype.moveTool_ = function (x, y, event) { - var coords = this.getSpriteCoordinates(x, y); - var currentFrame = this.piskelController.getCurrentFrame(); - - if (this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // Warning : do not call setCurrentButton here - // mousemove do not have the correct mouse button information on all browsers - this.currentToolBehavior.moveToolAt( - coords.x | 0, - coords.y | 0, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } else { - - this.currentToolBehavior.moveUnactiveToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - currentFrame, - this.overlayFrame, - event - ); - } - $.publish(Events.CURSOR_MOVED, [coords.x, coords.y]); - }; - - ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; - var delta = event.wheelDeltaY || (-2 * event.deltaY); - var modifier = Math.abs(delta/120); - if (delta > 0) { - this.increaseZoom_(modifier); - } else if (delta < 0) { - this.decreaseZoom_(modifier); - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onMouseup_ = function (event) { - if(this.isClicked) { - $.publish(Events.MOUSE_EVENT, [event, this]); - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - - this.isClicked = false; - this.setCurrentButton(event); - - var coords = this.getSpriteCoordinates(event.clientX, event.clientY); - this.currentToolBehavior.releaseToolAt( - coords.x, - coords.y, - this.getCurrentColor_(), - this.piskelController.getCurrentFrame(), - this.overlayFrame, - event - ); - - $.publish(Events.TOOL_RELEASED); - } - }; - - /** - * Translate absolute x,y screen coordinates into sprite coordinates - * @param {Number} screenX - * @param {Number} screenY - * @return {Object} {x:Number, y:Number} - */ - ns.DrawingController.prototype.getSpriteCoordinates = function(screenX, screenY) { - return this.renderer.getCoordinates(screenX, screenY); - }; - - ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) { - return this.renderer.reverseCoordinates(spriteX, spriteY); - }; - - ns.DrawingController.prototype.setCurrentButton = function (event) { - this.currentMouseButton_ = event.button; - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - // WARNING : Do not rely on the current event to get the current color! - // It might seem like a good idea, and works perfectly fine on Chrome - // Sadly Firefox and IE found clever, for some reason, to set event.button to 0 - // on a mouse move event - // This always matches a LEFT mouse button which is __really__ not helpful - - if(this.currentMouseButton_ == Constants.RIGHT_BUTTON) { - return this.paletteController.getSecondaryColor(); - } else if(this.currentMouseButton_ == Constants.LEFT_BUTTON) { - return this.paletteController.getPrimaryColor(); - } else { - return Constants.DEFAULT_PEN_COLOR; - } - }; - - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } - }; - - ns.DrawingController.prototype.render = function () { - var currentFrame = this.piskelController.getCurrentFrame(); - if (!currentFrame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); - } - - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.onionSkinRenderer.render(); - } - - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.layersRenderer.render(); - } - - this.renderer.render(currentFrame); - this.overlayRenderer.render(this.overlayFrame); - }; - - /** - * @private - */ - ns.DrawingController.prototype.calculateZoom_ = function() { - var frameHeight = this.piskelController.getCurrentFrame().getHeight(), - frameWidth = this.piskelController.getCurrentFrame().getWidth(); - - return Math.min(this.getAvailableWidth_()/frameWidth, this.getAvailableHeight_()/frameHeight); - }; - - ns.DrawingController.prototype.getAvailableHeight_ = function () { - return $('#main-wrapper').height(); - }; - - ns.DrawingController.prototype.getAvailableWidth_ = function () { - var leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - toolsContainerWidth = $('#tool-section').outerWidth(true), - settingsContainerWidth = $('#application-action-section').outerWidth(true), - availableWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth - toolsContainerWidth - settingsContainerWidth; - - var comfortMargin = 10; - return availableWidth - comfortMargin; - }; - - ns.DrawingController.prototype.getContainerHeight_ = function () { - return this.calculateZoom_() * this.piskelController.getCurrentFrame().getHeight(); - }; - - ns.DrawingController.prototype.getContainerWidth_ = function () { - return this.calculateZoom_() * this.piskelController.getCurrentFrame().getWidth(); - }; - - /** - * @private - */ - ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { - var containerHeight = this.getContainerHeight_(); - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); - $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px' - }); - }; - - ns.DrawingController.prototype.getRenderer = function () { - return this.compositeRenderer; - }; - - ns.DrawingController.prototype.setOffset = function (x, y) { - this.compositeRenderer.setOffset(x, y); - $.publish(Events.ZOOM_CHANGED); - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - var ACTION = { - SELECT : 'select', - CLONE : 'clone', - DELETE : 'delete', - NEW_FRAME : 'newframe' - }; - - ns.PreviewFilmController = function (piskelController, container) { - - this.piskelController = piskelController; - this.container = container; - this.refreshZoom_(); - - this.redrawFlag = true; - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); - }; - - ns.PreviewFilmController.prototype.init = function() { - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); - - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this)); - this.updateScrollerOverflows(); - }; - - ns.PreviewFilmController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; - - ns.PreviewFilmController.prototype.refreshZoom_ = function () { - this.zoom = this.calculateZoom_(); - }; - - ns.PreviewFilmController.prototype.render = function () { - if (this.redrawFlag) { - this.createPreviews_(); - this.redrawFlag = false; - } - }; - - ns.PreviewFilmController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; - - ns.PreviewFilmController.prototype.onContainerClick_ = function (event) { - var target = pskl.utils.Dom.getParentWithData(event.target, 'tileAction'); - if (!target) { - return; - } - var action = target.dataset.tileAction; - var index = parseInt(target.dataset.tileNumber, 10); - - if (action === ACTION.CLONE) { - this.piskelController.duplicateFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.DELETE) { - this.piskelController.removeFrameAt(index); - this.updateScrollerOverflows(); - } else if (action === ACTION.SELECT) { - this.piskelController.setCurrentFrameIndex(index); - } else if (action === ACTION.NEW_FRAME) { - this.piskelController.addFrame(); - this.updateScrollerOverflows(); - } - }; - - ns.PreviewFilmController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); - - var frameCount = this.piskelController.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME); - newFrameButton.innerHTML = "

        Add new frame

        "; - this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; - - - /** - * @private - */ - ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; - - /** - * @private - */ - ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); - - this.piskelController.moveFrame(originFrameId, targetInsertionId); - this.piskelController.setCurrentFrameIndex(targetInsertionId); - }; - - - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber); - - var previewTileRoot = document.createElement("li"); - previewTileRoot.setAttribute("data-tile-number", tileNumber); - previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); - previewTileRoot.classList.add("preview-tile"); - if (this.piskelController.getCurrentFrame() == currentFrame) { - previewTileRoot.classList.add("selected"); - } - - var canvasContainer = document.createElement("div"); - canvasContainer.classList.add("canvas-container", pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('data-tile-number', tileNumber); - cloneFrameButton.setAttribute('data-tile-action', ACTION.CLONE); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - - - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); - - if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = "tile-overlay delete-frame-action"; - previewTileRoot.appendChild(deleteButton); - - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber + 1; - previewTileRoot.appendChild(tileCount); - - return previewTileRoot; - }; - - ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - return canvas; - }; - - ns.PreviewFilmController.prototype.frameToPreviewCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - return canvas; - }; - - ns.PreviewFilmController.prototype.clonePreviewCanvas_ = function (canvas) { - var clone = pskl.CanvasUtils.clone(canvas); - clone.classList.add('tile-view', 'canvas'); - return clone; - }; - - /** - * Calculate the preview zoom depending on the piskel size - */ - ns.PreviewFilmController.prototype.calculateZoom_ = function () { - var curFrame = this.piskelController.getCurrentFrame(), - frameHeight = curFrame.getHeight(), - frameWidth = curFrame.getWidth(); - - return Math.min(Constants.PREVIEW_FILM_SIZE/frameHeight, Constants.PREVIEW_FILM_SIZE/frameWidth); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.LayersListController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.LayersListController.prototype.init = function () { - this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template'); - this.rootEl = document.querySelector('.layers-list-container'); - this.layersListEl = document.querySelector('.layers-list'); - this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview'); - - this.rootEl.addEventListener('click', this.onClick_.bind(this)); - this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this)); - - $.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+L', this.toggleLayerPreview_.bind(this)); - - this.renderLayerList_(); - this.updateToggleLayerPreview_(); - - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - }; - - ns.LayersListController.prototype.renderLayerList_ = function () { - this.layersListEl.innerHTML = ''; - var layers = this.piskelController.getLayers(); - layers.forEach(this.addLayerItem.bind(this)); - }; - - ns.LayersListController.prototype.updateToggleLayerPreview_ = function () { - var enabledClassname = 'layers-toggle-preview-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)) { - this.toggleLayerPreviewEl.classList.add(enabledClassname); - } else { - this.toggleLayerPreviewEl.classList.remove(enabledClassname); - } - }; - - ns.LayersListController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.LAYER_PREVIEW) { - this.updateToggleLayerPreview_(); - } - }; - - ns.LayersListController.prototype.addLayerItem = function (layer, index) { - var isSelected = this.piskelController.getCurrentLayer() === layer; - var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, { - 'layername' : layer.getName(), - 'layerindex' : index, - 'isselected:current-layer-item' : isSelected - }); - var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml); - this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild); - }; - - ns.LayersListController.prototype.onClick_ = function (evt) { - var el = evt.target || evt.srcElement; - var index; - if (el.classList.contains('button')) { - this.onButtonClick_(el); - } else if (el.classList.contains('layer-item')) { - index = el.dataset.layerIndex; - this.piskelController.setCurrentLayerIndex(parseInt(index, 10)); - } else if (el.classList.contains('edit-icon')) { - index = el.parentNode.dataset.layerIndex; - this.renameLayerAt_(index); - } - }; - - ns.LayersListController.prototype.renameLayerAt_ = function (index) { - var layer = this.piskelController.getLayerAt(index); - var name = window.prompt("Please enter the layer name", layer.getName()); - if (name) { - this.piskelController.renameLayerAt(index, name); - this.renderLayerList_(); - } - }; - - ns.LayersListController.prototype.onButtonClick_ = function (button) { - var action = button.getAttribute('data-action'); - if (action == 'up') { - this.piskelController.moveLayerUp(); - } else if (action == 'down') { - this.piskelController.moveLayerDown(); - } else if (action == 'add') { - this.piskelController.createLayer(); - } else if (action == 'delete') { - this.piskelController.removeCurrentLayer(); - } - }; - - ns.LayersListController.prototype.toggleLayerPreview_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW); - pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW, !currentValue); - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE - var PREVIEW_SIZE = 200; - - ns.AnimatedPreviewController = function (piskelController, container) { - this.piskelController = piskelController; - this.container = container; - - this.elapsedTime = 0; - this.currentIndex = 0; - - this.setFPS(Constants.DEFAULT.FPS); - - var frame = this.piskelController.getCurrentFrame(); - - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); - }; - - ns.AnimatedPreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); - document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - - this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin"); - this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); - - $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - - this.updateZoom_(); - this.updateOnionSkinPreview_(); - }; - - ns.AnimatedPreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { - if (name == pskl.UserSettings.ONION_SKIN) { - this.updateOnionSkinPreview_(); - } else { - this.updateZoom_(); - this.updateContainerDimensions_(); - } - }; - - ns.AnimatedPreviewController.prototype.updateOnionSkinPreview_ = function () { - var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } - }; - - ns.AnimatedPreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); - this.renderer.setZoom(zoom); - }; - - ns.AnimatedPreviewController.prototype.getZoom = function () { - return this.calculateZoom_(); - }; - - ns.AnimatedPreviewController.prototype.getCoordinates = function(x, y) { - var containerOffset = this.container.offset(); - x = x - containerOffset.left; - y = y - containerOffset.top; - var zoom = this.getZoom(); - return { - x : Math.floor(x / zoom), - y : Math.floor(y / zoom) - }; - }; - - ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt($("#preview-fps")[0].value, 10)); - }; - - ns.AnimatedPreviewController.prototype.setFPS = function (fps) { - if (fps) { - this.fps = fps; - $("#preview-fps").val(this.fps); - $("#display-fps").html(this.fps + " FPS"); - } - }; - - ns.AnimatedPreviewController.prototype.getFPS = function () { - return this.fps; - }; - - ns.AnimatedPreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (index != this.currentIndex) { - this.currentIndex = index; - if (!this.piskelController.hasFrameAt(this.currentIndex)) { - this.currentIndex = 0; - this.elapsedTime = 0; - } - var frame = this.piskelController.getFrameAt(this.currentIndex); - this.renderer.render(frame); - } - }; - - /** - * Calculate the preview zoom depending on the framesheet size - */ - ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { - var frame = this.piskelController.getCurrentFrame(); - var previewSize = 200, - hZoom = previewSize / frame.getHeight(), - wZoom = previewSize / frame.getWidth(); - - return Math.min(hZoom, wZoom); - }; - - ns.AnimatedPreviewController.prototype.onFrameSizeChange_ = function () { - this.updateZoom_(); - this.updateContainerDimensions_(); - }; - - ns.AnimatedPreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var height, width; - - if (isTiled) { - height = PREVIEW_SIZE; - width = PREVIEW_SIZE; - } else { - var zoom = this.getZoom(); - var frame = this.piskelController.getCurrentFrame(); - height = frame.getHeight() * zoom; - width = frame.getWidth() * zoom; - } - - containerEl.style.height = height + "px"; - containerEl.style.width = width + "px"; - containerEl.style.marginTop = ((PREVIEW_SIZE - height) / 2) + "px"; - containerEl.style.marginBottom = ((PREVIEW_SIZE - height) / 2) + "px"; - containerEl.style.marginLeft = ((PREVIEW_SIZE - width) / 2) + "px"; - containerEl.style.marginRight = ((PREVIEW_SIZE - width) / 2) + "px"; - }; - - ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () { - var currentValue = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); - pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN, !currentValue); - }; -})();;(function () { - var ns = $.namespace('pskl.controller'); - - ns.MinimapController = function (piskelController, animationController, drawingController, container) { - this.piskelController = piskelController; - this.animationController = animationController; - this.drawingController = drawingController; - this.container = container; - - this.isClicked = false; - }; - - ns.MinimapController.prototype.init = function () { - // Create minimap DOM elements - this.cropFrame = document.createElement('DIV'); - this.cropFrame.className = 'minimap-crop-frame'; - this.cropFrame.style.display = 'none'; - $(this.container).append(this.cropFrame); - - // Init mouse events - $(this.container).mousedown(this.onMinimapMousedown_.bind(this)); - $('body').mousemove(this.onMinimapMousemove_.bind(this)); - $('body').mouseup(this.onMinimapMouseup_.bind(this)); - - $.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this)); - }; - - ns.MinimapController.prototype.renderMinimap_ = function () { - var zoomRatio = this.getDrawingAreaZoomRatio_(); - if (zoomRatio > 1) { - this.displayCropFrame_(zoomRatio, this.drawingController.getRenderer().getOffset()); - } else { - this.hideCropFrame_(); - } - }; - - ns.MinimapController.prototype.displayCropFrame_ = function (ratio, offset) { - this.cropFrame.style.display = 'block'; - this.cropFrame.style.top = (offset.y * this.animationController.getZoom()) + 'px'; - this.cropFrame.style.left = (offset.x * this.animationController.getZoom()) + 'px'; - var zoomRatio = this.getDrawingAreaZoomRatio_(); - this.cropFrame.style.width = (this.container.width() / zoomRatio) + 'px'; - this.cropFrame.style.height = (this.container.height() / zoomRatio) + 'px'; - - }; - - ns.MinimapController.prototype.hideCropFrame_ = function () { - this.cropFrame.style.display = 'none'; - }; - - ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) { - if (this.isClicked) { - if (this.getDrawingAreaZoomRatio_() > 1) { - var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY); - this.drawingController.setOffset(coords.x, coords.y); - } - } - }; - - ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) { - this.isClicked = true; - }; - - ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) { - this.isClicked = false; - }; - - ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) { - var frameCoords = this.animationController.getCoordinates(x, y); - var zoomRatio = this.getDrawingAreaZoomRatio_(); - var frameWidth = this.piskelController.getCurrentFrame().getWidth(); - var frameHeight = this.piskelController.getCurrentFrame().getHeight(); - - var width = frameWidth / zoomRatio; - var height = frameHeight / zoomRatio; - - return { - x : frameCoords.x - (width/2), - y : frameCoords.y - (height/2) - }; - }; - - ns.MinimapController.prototype.getDrawingAreaZoomRatio_ = function () { - var drawingAreaZoom = this.drawingController.getRenderer().getZoom(); - var drawingAreaFullHeight = this.piskelController.getCurrentFrame().getHeight() * drawingAreaZoom; - var zoomRatio = drawingAreaFullHeight / this.drawingController.getRenderer().getDisplaySize().height; - - return zoomRatio; - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - var toDescriptor = function (id, shortcut, instance) { - return {id:id, shortcut:shortcut, instance:instance}; - }; - - this.tools = [ - toDescriptor('simplePen', 'P', new pskl.drawingtools.SimplePen()), - toDescriptor('verticalMirrorPen', 'V', new pskl.drawingtools.VerticalMirrorPen()), - toDescriptor('paintBucket', 'B', new pskl.drawingtools.PaintBucket()), - toDescriptor('colorSwap', 'A', new pskl.drawingtools.ColorSwap()), - toDescriptor('eraser', 'E', new pskl.drawingtools.Eraser()), - toDescriptor('stroke', 'L', new pskl.drawingtools.Stroke()), - toDescriptor('rectangle', 'R', new pskl.drawingtools.Rectangle()), - toDescriptor('circle', 'C', new pskl.drawingtools.Circle()), - toDescriptor('move', 'M', new pskl.drawingtools.Move()), - toDescriptor('rectangleSelect', 'S', new pskl.drawingtools.RectangleSelect()), - toDescriptor('shapeSelect', 'Z', new pskl.drawingtools.ShapeSelect()), - toDescriptor('lighten', 'U', new pskl.drawingtools.Lighten()), - toDescriptor('colorPicker', 'O', new pskl.drawingtools.ColorPicker()) - ]; - - this.currentSelectedTool = this.tools[0]; - this.previousSelectedTool = this.tools[0]; - }; - - /** - * @public - */ - ns.ToolController.prototype.init = function() { - this.createToolsDom_(); - this.addKeyboardShortcuts_(); - - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.tools[0]); - // Activate listener on tool panel: - $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); - - $.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this)); - }; - - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - stage.removeClass(pskl.drawingtools.Move.TOOL_ID); - } - stage.addClass(tool.instance.toolId); - stage.data("selected-tool-class", tool.instance.toolId); - }; - - ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) { - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - }; - - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - - var selectedToolElement = $('#tool-section .tool-icon.selected'); - var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']'); - - selectedToolElement.removeClass('selected'); - toolElement.addClass('selected'); - - $.publish(Events.TOOL_SELECTED, [tool.instance]); - }; - - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); - - if(clickedTool.length) { - var toolId = clickedTool.data().toolId; - var tool = this.getToolById_(toolId); - if (tool) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) { - for (var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) { - this.selectTool_(tool); - } - } - }; - - ns.ToolController.prototype.getToolById_ = function (toolId) { - for(var i = 0 ; i < this.tools.length ; i++) { - var tool = this.tools[i]; - if (tool.instance.toolId == toolId) { - return tool; - } - } - return null; - }; - - /** - * @private - */ - ns.ToolController.prototype.createToolsDom_ = function() { - var toolMarkup = ''; - for(var i = 0 ; i < this.tools.length ; i++) { - toolMarkup += this.getToolMarkup_(this.tools[i]); - } - $('#tools-container').html(toolMarkup); - }; - - /** - * @private - */ - ns.ToolController.prototype.getToolMarkup_ = function(tool) { - var toolId = tool.instance.toolId; - - var classList = ['tool-icon', toolId]; - if (this.currentSelectedTool == tool) { - classList.push('selected'); - } - - var tpl = pskl.utils.Template.get('drawing-tool-item-template'); - return pskl.utils.Template.replace(tpl, { - cssclass : classList.join(' '), - toolid : toolId, - title : tool.instance.getTooltipText(tool.shortcut) - }); - }; - - ns.ToolController.prototype.addKeyboardShortcuts_ = function () { - for(var i = 0 ; i < this.tools.length ; i++) { - pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this)); - } - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.PaletteController = function () { - this.primaryColor = Constants.DEFAULT_PEN_COLOR; - this.secondaryColor = Constants.TRANSPARENT_COLOR; - }; - - /** - * @public - */ - ns.PaletteController.prototype.init = function() { - $.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true})); - $.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false})); - - pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this)); - pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this)); - - var spectrumCfg = { - showPalette: true, - showButtons: false, - showInput: true, - palette: [ - ['rgba(0,0,0,0)'] - ], - clickoutFiresChange : true, - - beforeShow : function(tinycolor) { - tinycolor.setAlpha(1); - } - }; - - // Initialize colorpickers: - var colorPicker = $('#color-picker'); - colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg)); - colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker); - - var secondaryColorPicker = $('#secondary-color-picker'); - secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg)); - secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); - this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); - - var swapColorsIcon = $('.swap-colors-icon'); - swapColorsIcon.click(this.swapColors.bind(this)); - }; - - /** - * @private - */ - ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) { - var inputPicker = $(evt.target); - if(evt.data.isPrimary) { - this.setPrimaryColor(inputPicker.val()); - } else { - this.setSecondaryColor(inputPicker.val()); - } - }; - - /** - * @private - */ - ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) { - var inputPicker = $(evt.target); - if(args.isPrimary) { - this.setPrimaryColor(color); - } else { - this.setSecondaryColor(color); - } - }; - - ns.PaletteController.prototype.setPrimaryColor = function (color) { - this.primaryColor = color; - this.updateColorPicker_(color, $('#color-picker')); - $.publish(Events.PRIMARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.setSecondaryColor = function (color) { - this.secondaryColor = color; - this.updateColorPicker_(color, $('#secondary-color-picker')); - $.publish(Events.SECONDARY_COLOR_SELECTED, [color]); - }; - - ns.PaletteController.prototype.getPrimaryColor = function () { - return this.primaryColor; - }; - - ns.PaletteController.prototype.getSecondaryColor = function () { - return this.secondaryColor; - }; - - ns.PaletteController.prototype.swapColors = function () { - var primaryColor = this.getPrimaryColor(); - this.setPrimaryColor(this.getSecondaryColor()); - this.setSecondaryColor(primaryColor); - }; - - ns.PaletteController.prototype.resetColors = function () { - this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR); - this.setSecondaryColor(Constants.TRANSPARENT_COLOR); - }; - - /** - * @private - */ - ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) { - if (color == Constants.TRANSPARENT_COLOR) { - // We can set the current palette color to transparent. - // You can then combine this transparent color with an advanced - // tool for customized deletions. - // Eg: bucket + transparent: Delete a colored area - // Stroke + transparent: hollow out the equivalent of a stroke - - // The colorpicker can't be set to a transparent state. - // We set its background to white and insert the - // string "TRANSPARENT" to mimic this state: - colorPicker.spectrum("set", Constants.TRANSPARENT_COLOR); - colorPicker.val(Constants.TRANSPARENT_COLOR); - } else { - colorPicker.spectrum("set", color); - } - this.setTitleOnPicker_(color, colorPicker); - }; - - ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) { - var spectrumInputSelector = '.sp-replacer'; - colorPicker.next(spectrumInputSelector).attr('title', title); - }; -})(); - - - -;(function () { - var ns = $.namespace('pskl.controller'); - - var PRIMARY_COLOR_CLASSNAME = 'palettes-list-primary-color'; - var SECONDARY_COLOR_CLASSNAME = 'palettes-list-secondary-color'; - - var HAS_SCROLL_CLASSNAME = 'palettes-list-has-scrollbar'; - // well ... I know that if there are more than 20 colors, a scrollbar will be displayed - // It's linked to the max-height: 160px; defined in toolbox-palette-list.css ! - // I apologize to my future self for this one. - var NO_SCROLL_MAX_COLORS = 20; - - - ns.PalettesListController = function (paletteController, usedColorService) { - this.usedColorService = usedColorService; - this.paletteService = pskl.app.paletteService; - this.paletteController = paletteController; - }; - - ns.PalettesListController.prototype.init = function () { - this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); - - this.colorListContainer_ = document.querySelector('.palettes-list-colors'); - this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - - var createPaletteButton_ = document.querySelector('.create-palette-button'); - var paletteActions = document.querySelector('.palette-actions'); - - this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); - this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); - this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - - createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - paletteActions.addEventListener('click', this.onPaletteActionsClick_.bind(this)); - - - $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); - $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); - $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); - - this.fillPaletteList(); - this.selectPaletteFromUserSettings(); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = [{ - id : Constants.CURRENT_COLORS_PALETTE_ID, - name : 'Current colors' - }]; - palettes = palettes.concat(this.paletteService.getPalettes()); - - var html = palettes.map(function (palette) { - return pskl.utils.Template.replace('', palette); - }).join(''); - this.colorPaletteSelect_.innerHTML = html; - }; - - ns.PalettesListController.prototype.fillColorListContainer = function () { - var colors = this.getSelectedPaletteColors_(); - - var html = colors.map(function (color) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color}); - }.bind(this)).join(''); - this.colorListContainer_.innerHTML = html; - - this.highlightSelectedColors(); - - var hasScrollbar = colors.length > NO_SCROLL_MAX_COLORS; - if (hasScrollbar && !pskl.utils.UserAgent.isChrome) { - this.colorListContainer_.classList.add(HAS_SCROLL_CLASSNAME); - } else { - this.colorListContainer_.classList.remove(HAS_SCROLL_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { - var colors = []; - var paletteId = this.colorPaletteSelect_.value; - if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { - colors = this.usedColorService.getCurrentColors(); - } else { - var palette = this.paletteService.getPaletteById(paletteId); - if (palette) { - colors = palette.colors; - } - } - - if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { - colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - } - - return colors; - }; - - ns.PalettesListController.prototype.selectPaletteFromUserSettings = function () { - this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE)); - }; - - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - this.colorPaletteSelect_.value = paletteId; - }; - - ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { - var paletteId = this.colorPaletteSelect_.value; - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - this.fillColorListContainer(); - }; - - ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); - }; - - ns.PalettesListController.prototype.onPaletteActionsClick_ = function (evt) { - var classList = evt.target.classList; - if (classList.contains('palette-action-edit')) { - this.editSelectedPalette_(); - } else if (classList.contains('palette-action-delete')) { - this.deleteSelectedPalette_(); - } else if (classList.contains('palette-action-download')) { - this.downloadSelectedPalette_(); - } - }; - - ns.PalettesListController.prototype.editSelectedPalette_ = function () { - var paletteId = this.colorPaletteSelect_.value; - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : paletteId - }); - }; - - ns.PalettesListController.prototype.deleteSelectedPalette_ = function () { - var paletteId = this.colorPaletteSelect_.value; - var palette = this.paletteService.getPaletteById(paletteId); - if (window.confirm('Are you sure you want to delete palette ' + palette.name)) { - this.paletteService.deletePaletteById(palette.id); - this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID); - } - }; - - ns.PalettesListController.prototype.downloadSelectedPalette_ = function () { - window.alert('not implemented yet'); - }; - - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { - event.preventDefault(); - }; - - ns.PalettesListController.prototype.onColorContainerMouseup = function (event) { - var target = event.target; - var color = target.dataset.color; - - if (color) { - if (event.button == Constants.LEFT_BUTTON) { - $.publish(Events.SELECT_PRIMARY_COLOR, [color]); - } else if (event.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SELECT_SECONDARY_COLOR, [color]); - } - } - }; - - ns.PalettesListController.prototype.highlightSelectedColors = function () { - this.removeClass_(PRIMARY_COLOR_CLASSNAME); - this.removeClass_(SECONDARY_COLOR_CLASSNAME); - - var colorContainer = this.getColorContainer_(this.paletteController.getSecondaryColor()); - if (colorContainer) { - colorContainer.classList.remove(PRIMARY_COLOR_CLASSNAME); - colorContainer.classList.add(SECONDARY_COLOR_CLASSNAME); - } - - colorContainer = this.getColorContainer_(this.paletteController.getPrimaryColor()); - if (colorContainer) { - colorContainer.classList.remove(SECONDARY_COLOR_CLASSNAME); - colorContainer.classList.add(PRIMARY_COLOR_CLASSNAME); - } - }; - - ns.PalettesListController.prototype.getColorContainer_ = function (color) { - return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+color+'"]'); - }; - - ns.PalettesListController.prototype.removeClass_ = function (cssClass) { - var element = document.querySelector('.' + cssClass); - if (element) { - element.classList.remove(cssClass); - } - }; - - ns.PalettesListController.prototype.onPaletteListUpdated = function () { - this.fillPaletteList(); - this.selectPaletteFromUserSettings(); - this.fillColorListContainer(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller"); - - ns.NotificationController = function () {}; - - /** - * @public - */ - ns.NotificationController.prototype.init = function() { - $.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this)); - $.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this)); - }; - - /** - * @private - */ - ns.NotificationController.prototype.displayMessage_ = function (evt, messageInfo) { - this.removeMessage_(); - - var message = document.createElement('div'); - message.id = "user-message"; - message.className = "user-message"; - message.innerHTML = messageInfo.content; - message.innerHTML = message.innerHTML + "
        x
        "; - document.body.appendChild(message); - $(message).find(".close").click($.proxy(this.removeMessage_, this)); - if(messageInfo.behavior) { - messageInfo.behavior(message); - } - }; - - /** - * @private - */ - ns.NotificationController.prototype.removeMessage_ = function (evt) { - var message = $("#user-message"); - if (message.length) { - message.remove(); - } - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller'); - - ns.CanvasBackgroundController = function () { - this.body = document.body; - }; - - ns.CanvasBackgroundController.prototype.init = function () { - $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); - this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); - }; - - - ns.CanvasBackgroundController.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - ns.CanvasBackgroundController.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.body.dataset.currentBackgroundClass; - if (currentClass) { - this.body.classList.remove(currentClass); - } - this.body.classList.add(newClass); - this.body.dataset.currentBackgroundClass = newClass; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ApplicationSettingsController = function () {}; - - /** - * @public - */ - ns.ApplicationSettingsController.prototype.init = function() { - // Highlight selected background picker: - var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - $('#background-picker-wrapper') - .find('.background-picker[data-background-class=' + backgroundClass + ']') - .addClass('selected'); - - // Grid display and size - var gridWidth = pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH); - $('#grid-width').val(gridWidth); - $('#grid-width').change(this.onGridWidthChange.bind(this)); - - // Handle canvas background changes: - $('#background-picker-wrapper').click(this.onBackgroundClick.bind(this)); - }; - - ns.ApplicationSettingsController.prototype.onGridWidthChange = function (evt) { - var width = $('#grid-width').val(); - pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, parseInt(width, 10)); - }; - - ns.ApplicationSettingsController.prototype.onBackgroundClick = function (evt) { - var target = $(evt.target).closest('.background-picker'); - if (target.length) { - var backgroundClass = target.data('background-class'); - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); - - $('.background-picker').removeClass('selected'); - target.addClass('selected'); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ResizeController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.ResizeController.prototype.init = function () { - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - - this.resizeWidth.val(this.piskelController.getWidth()); - this.resizeHeight.val(this.piskelController.getHeight()); - - this.cancelButton = $('.resize-cancel-button'); - this.cancelButton.click(this.onCancelButtonClicked_.bind(this)); - - this.resizeForm = $("[name=resize-form]"); - this.resizeForm.submit(this.onResizeFormSubmit_.bind(this)); - - this.resizeContentCheckbox = $(".resize-content-checkbox"); - }; - - ns.ResizeController.prototype.onResizeFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - - var width = parseInt(this.resizeWidth.val(), 10); - var height = parseInt(this.resizeHeight.val(), 10); - - var resizeContentEnabled = this.isResizeContentEnabled_(); - var resizedLayers = this.piskelController.getLayers().map(this.resizeLayer_.bind(this)); - - var piskel = pskl.model.Piskel.fromLayers(resizedLayers, this.piskelController.getPiskel().getDescriptor()); - - pskl.app.piskelController.setPiskel(piskel, true); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - - ns.ResizeController.prototype.resizeLayer_ = function (layer) { - var resizedFrames = layer.getFrames().map(this.resizeFrame_.bind(this)); - return pskl.model.Layer.fromFrames(layer.getName(), resizedFrames); - }; - - ns.ResizeController.prototype.resizeFrame_ = function (frame) { - var width = parseInt(this.resizeWidth.val(), 10); - var height = parseInt(this.resizeHeight.val(), 10); - - var resizedFrame; - if (this.isResizeContentEnabled_()) { - resizedFrame = pskl.utils.FrameUtils.resize(frame, width, height, false); - } else { - resizedFrame = new pskl.model.Frame(width, height); - frame.forEachPixel(function (color, x, y) { - if (x < resizedFrame.getWidth() && y < resizedFrame.getHeight()) { - resizedFrame.setPixel(x, y, color); - } - }); - } - - return resizedFrame; - }; - - ns.ResizeController.prototype.isResizeContentEnabled_ = function () { - return !!this.resizeContentCheckbox.prop('checked'); - }; - - ns.ResizeController.prototype.onCancelButtonClicked_ = function (evt) { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - ns.ImageExportController = function (piskelController) { - this.piskelController = piskelController; - this.pngExportController = new ns.PngExportController(piskelController); - this.gifExportController = new ns.GifExportController(piskelController); - }; - - ns.ImageExportController.prototype.init = function () { - this.pngExportController.init(); - this.gifExportController.init(); - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - var URL_MAX_LENGTH = 30; - var MAX_GIF_COLORS = 256; - var MAX_EXPORT_ZOOM = 20; - var DEFAULT_EXPORT_ZOOM = 10; - - ns.GifExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * List of Resolutions applicable for Gif export - * @static - * @type {Array} array of Objects {zoom:{Number}, default:{Boolean}} - */ - ns.GifExportController.RESOLUTIONS = []; - for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) { - ns.GifExportController.RESOLUTIONS.push({ - zoom : i - }); - } - - ns.GifExportController.prototype.init = function () { - this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template"); - - this.uploadStatusContainerEl = document.querySelector(".gif-upload-status"); - - this.previewContainerEl = document.querySelector(".gif-export-preview"); - this.selectResolutionEl = document.querySelector(".gif-export-select-resolution"); - - this.uploadButton = $(".gif-upload-button"); - this.uploadButton.click(this.onUploadButtonClick_.bind(this)); - - this.downloadButton = $(".gif-download-button"); - this.downloadButton.click(this.onDownloadButtonClick_.bind(this)); - - this.exportProgressStatusEl = document.querySelector('.gif-export-progress-status'); - this.exportProgressBarEl = document.querySelector('.gif-export-progress-bar'); - - this.createOptionElements_(); - }; - - ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { - evt.originalEvent.preventDefault(); - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, this.onGifRenderingCompleted_.bind(this)); - }; - - ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { - var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; - var zoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(); - - this.renderAsImageDataAnimatedGIF(zoom, fps, function (imageData) { - pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }.bind(this)); - }; - - ns.GifExportController.prototype.onGifRenderingCompleted_ = function (imageData) { - this.updatePreview_(imageData); - this.previewContainerEl.classList.add("preview-upload-ongoing"); - pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this)); - }; - - ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.GifExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = "
        "; - }; - - ns.GifExportController.prototype.getSelectedZoom_ = function () { - return this.selectResolutionEl.value; - }; - - ns.GifExportController.prototype.createOptionElements_ = function () { - var resolutions = ns.GifExportController.RESOLUTIONS; - for (var i = 0 ; i < resolutions.length ; i++) { - var option = this.createOptionForResolution_(resolutions[i]); - this.selectResolutionEl.appendChild(option); - } - }; - - ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) { - var zoom = resolution.zoom; - var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight(); - var value = zoom; - - var isSelected = zoom === DEFAULT_EXPORT_ZOOM; - var selected = isSelected ? 'selected' : ''; - var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label, selected : selected}); - var optionEl = pskl.utils.Template.createFromHTML(optionHTML); - - return optionEl; - }; - - ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { - var colorCount = pskl.app.currentColorsService.getCurrentColors().length; - var preserveColors = colorCount < MAX_GIF_COLORS; - var gif = new window.GIF({ - workers: 2, - quality: 1, - width: this.piskelController.getWidth()*zoom, - height: this.piskelController.getHeight()*zoom, - preserveColors : preserveColors - }); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - var canvas = canvasRenderer.render(); - gif.addFrame(canvas.getContext('2d'), { - delay: 1000 / fps - }); - } - - gif.on('progress', function(percentage) { - this.updateProgressStatus_((percentage*100).toFixed(2)); - }.bind(this)); - - gif.on('finished', function(blob) { - this.hideProgressStatus_(); - pskl.utils.FileUtils.readFile(blob, cb); - }.bind(this)); - - gif.render(); - }; - - ns.GifExportController.prototype.updateProgressStatus_ = function (percentage) { - this.exportProgressStatusEl.innerHTML = percentage + '%'; - this.exportProgressBarEl.style.width = percentage + "%"; - - }; - - ns.GifExportController.prototype.hideProgressStatus_ = function () { - this.exportProgressStatusEl.innerHTML = ''; - this.exportProgressBarEl.style.width = "0"; - }; - - // FIXME : HORRIBLE COPY/PASTA - - ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - var index = Math.round((maxLength-suffix.length) / 2); - var part1 = url.substring(0, index); - var part2 = url.substring(url.length - index, url.length); - url = part1 + suffix + part2; - } - return url; - }; -})();;(function () { - var ns = $.namespace("pskl.controller.settings"); - - var URL_MAX_LENGTH = 60; - - ns.PngExportController = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.PngExportController.prototype.init = function () { - this.previewContainerEl = document.querySelector(".png-export-preview"); - this.pngFilePrefixInput = document.getElementById('zip-prefix-name'); - this.pngFilePrefixInput.value = 'sprite_'; - - document.querySelector(".png-download-button").addEventListener('click', this.onPngDownloadButtonClick_.bind(this)); - - document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this)); - - this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png")); - }; - - ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { - var fileName = this.getPiskelName_() + '.png'; - pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }); - }; - - ns.PngExportController.prototype.onZipButtonClick_ = function () { - var zip = new window.JSZip(); - - for (var i = 0; i < this.piskelController.getFrameCount(); i++) { - var frame = this.piskelController.getFrameAt(i); - var canvas = this.getFrameAsCanvas_(frame); - var basename = this.pngFilePrefixInput.value; - var filename = basename + (i+1) + ".png"; - zip.file(filename, pskl.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); - } - - var fileName = this.getPiskelName_() + '.zip'; - - var blob = zip.generate({type:"blob"}); - pskl.utils.FileUtils.downloadAsFile(blob, fileName); - }; - - ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - return canvasRenderer.render(); - }; - - ns.PngExportController.prototype.getPiskelName_ = function () { - return this.piskelController.getPiskel().getDescriptor().name; - }; - - ns.PngExportController.prototype.getFramesheetAsCanvas = function () { - var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - return renderer.renderAsCanvas(); - }; - - ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { - this.updatePreview_(imageUrl); - this.updateStatus_(imageUrl); - this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; - - ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) { - if (imageUrl) { - var linkTpl = "{{shortLink}}"; - var linkHtml = pskl.utils.Template.replace(linkTpl, { - link : imageUrl, - shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...') - }); - this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml; - } else { - // FIXME : Should display error message instead - } - }; - - ns.PngExportController.prototype.updatePreview_ = function (src) { - this.previewContainerEl.innerHTML = ""; - }; - - ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) { - if (url.length > maxLength) { - url = url.substring(0, maxLength); - url += suffix; - } - return url; - }; -})(); -;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.SaveController = function (piskelController) { - this.piskelController = piskelController; - }; - - /** - * @public - */ - ns.SaveController.prototype.init = function () { - - // Only available in app-engine mode ... - this.piskelName = document.querySelector('.piskel-name'); - - this.saveOnlineStatus = $('#save-online-status'); - - this.saveFileStatus = $('#save-file-status'); - this.timestamp = new Date(); - - var descriptor = this.piskelController.getPiskel().getDescriptor(); - this.descriptionInput = $('#save-description'); - this.descriptionInput.val(descriptor.description); - - this.isPublicCheckbox = $('input[name=save-public-checkbox]'); - this.isPublicCheckbox.prop('checked', descriptor.isPublic); - - this.saveFileButton = $('#save-file-button'); - this.saveFileButton.click(this.saveFile_.bind(this)); - - this.saveLocalButton = $('#save-browser-button'); - this.saveLocalButton.click(this.saveLocal_.bind(this)); - - this.saveOnlineButton = $('#save-online-button'); - this.saveOnlineButton.click(this.saveOnline_.bind(this)); - - this.saveForm = $('form[name=save-form]'); - this.saveForm.submit(this.onSaveFormSubmit_.bind(this)); - - this.nameInput = $('#save-name'); - this.nameInput.val(descriptor.name); - this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this)); - - if (!pskl.app.isLoggedIn()) { - this.saveOnlineButton.hide(); - $('.save-public-section').hide(); - this.saveOnlineStatus.html(pskl.utils.Template.get('save-please-login-partial')); - } else { - this.saveOnlineStatus.html(pskl.utils.Template.get('save-online-status-partial')); - } - - this.updateLocalStatusFilename_(); - }; - - ns.SaveController.prototype.updateLocalStatusFilename_ = function () { - this.saveFileStatus.html(pskl.utils.Template.getAndReplace('save-file-status-template', { - name : this.getLocalFilename_() - })); - }; - - ns.SaveController.prototype.getLocalFilename_ = function () { - var piskelName = this.getName(); - var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}"); - return piskelName + "-" + timestamp + ".piskel"; - }; - - ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { - evt.preventDefault(); - evt.stopPropagation(); - - if (pskl.app.isLoggedIn()) { - this.saveOnline_(); - } else { - this.saveLocal_(); - } - - }; - - ns.SaveController.prototype.saveOnline_ = function () { - var name = this.getName(); - - if (!name) { - name = window.prompt('Please specify a name', 'New piskel'); - } - - if (name) { - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - - this.beforeSaving_(); - - this.saveOnlineButton.attr('disabled', true); - this.saveOnlineStatus.html('Saving ...'); - - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterOnlineSaving_.bind(this) - }); - } - }; - - ns.SaveController.prototype.saveLocal_ = function () { - var localStorageService = pskl.app.localStorageService; - var isOk = true; - var name = this.getName(); - var description = this.getDescription(); - if (localStorageService.getPiskel(name)) { - isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); - } - - if (isOk) { - this.beforeSaving_(); - localStorageService.save(name, description, pskl.app.piskelController.serialize()); - window.setTimeout(function () { - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), 500); - } - }; - - ns.SaveController.prototype.saveFile_ = function () { - this.beforeSaving_(); - pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_()); - this.onSaveSuccess_(); - this.afterSaving_(); - }.bind(this), "application/piskel+json"); - }; - - ns.SaveController.prototype.getName = function () { - return this.nameInput.val(); - }; - - ns.SaveController.prototype.getDescription = function () { - return this.descriptionInput.val(); - }; - - ns.SaveController.prototype.beforeSaving_ = function () { - this.updatePiskelDescriptor_(); - - if (this.piskelName) { - this.piskelName.classList.add('piskel-name-saving'); - } - }; - - ns.SaveController.prototype.updatePiskelDescriptor_ = function () { - var name = this.getName(); - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); - }; - - ns.SaveController.prototype.onSaveSuccess_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); - $.publish(Events.PISKEL_SAVED); - }; - - ns.SaveController.prototype.onSaveError_ = function (status) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+status+")"}]); - }; - - ns.SaveController.prototype.afterOnlineSaving_ = function () { - this.saveOnlineButton.attr('disabled', false); - this.saveOnlineStatus.html(''); - this.afterSaving_(); - }; - - ns.SaveController.prototype.afterSaving_ = function () { - if (this.piskelName) { - this.piskelName.classList.remove('piskel-name-saving'); - } - - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - ns.ImportController = function (piskelController) { - this.piskelController = piskelController; - this.importedImage_ = null; - }; - - ns.ImportController.prototype.init = function () { - this.browseLocalButton = document.querySelector('.browse-local-button'); - this.browseLocalButton.addEventListener('click', this.onBrowseLocalClick_.bind(this)); - - this.hiddenFileInput = $('[name=file-upload-input]'); - this.hiddenFileInput.change(this.onFileUploadChange_.bind(this)); - - this.fileInputButton = $('.file-input-button'); - this.fileInputButton.click(this.onFileInputClick_.bind(this)); - - this.hiddenOpenPiskelInput = $('[name=open-piskel-input]'); - this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this)); - - this.openPiskelInputButton = $('.open-piskel-button'); - this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this)); - - this.prevSessionContainer = $('.previous-session'); - this.previousSessionTemplate_ = pskl.utils.Template.get("previous-session-info-template"); - this.fillRestoreSession_(); - }; - - ns.ImportController.prototype.closeDrawer_ = function () { - $.publish(Events.CLOSE_SETTINGS_DRAWER); - }; - ns.ImportController.prototype.onFileUploadChange_ = function (evt) { - this.importPictureFromFile_(); - }; - - ns.ImportController.prototype.onFileInputClick_ = function (evt) { - this.hiddenFileInput.click(); - }; - - ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { - var files = this.hiddenOpenPiskelInput.get(0).files; - if (files.length == 1) { - this.openPiskelFile_(files[0]); - } - }; - - ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { - this.hiddenOpenPiskelInput.click(); - }; - - ns.ImportController.prototype.onBrowseLocalClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'browse-local'); - this.closeDrawer_(); - }; - - ns.ImportController.prototype.openPiskelFile_ = function (file) { - if (this.isPiskel_(file)){ - pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - this.closeDrawer_(); - } - }; - - ns.ImportController.prototype.importPictureFromFile_ = function () { - var files = this.hiddenFileInput.get(0).files; - if (files.length == 1) { - var file = files[0]; - if (this.isImage_(file)) { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'import-image', - initArgs : file - }); - this.closeDrawer_(); - } else { - this.closeDrawer_(); - throw 'File is not an image : ' + file.type; - } - } - }; - - ns.ImportController.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.ImportController.prototype.isPiskel_ = function (file) { - return (/\.piskel$/).test(file.name); - }; - - ns.ImportController.prototype.fillRestoreSession_ = function () { - var previousInfo = pskl.app.backupService.getPreviousPiskelInfo(); - if (previousInfo) { - var info = { - name : previousInfo.name, - date : pskl.utils.DateUtils.format(previousInfo.date, "{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}") - }; - - this.prevSessionContainer.html(pskl.utils.Template.replace(this.previousSessionTemplate_, info)); - $(".restore-session-button").click(this.onRestorePreviousSessionClick_.bind(this)); - } else { - this.prevSessionContainer.html("No piskel backup was found on this browser."); - } - }; - - ns.ImportController.prototype.onRestorePreviousSessionClick_ = function () { - if (window.confirm('This will erase your current workspace. Continue ?')) { - pskl.app.backupService.load(); - $.publish(Events.CLOSE_SETTINGS_DRAWER); - } - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.settings'); - - var settings = { - 'user' : { - template : 'templates/settings/application.html', - controller : ns.ApplicationSettingsController - }, - 'resize' : { - template : 'templates/settings/resize.html', - controller : ns.ResizeController - }, - 'export' : { - template : 'templates/settings/export.html', - controller : ns.ImageExportController - }, - 'import' : { - template : 'templates/settings/import.html', - controller : ns.ImportController - }, - 'localstorage' : { - template : 'templates/settings/localstorage.html', - controller : ns.LocalStorageController - }, - 'save' : { - template : 'templates/settings/save.html', - controller : ns.SaveController - } - }; - - var SEL_SETTING_CLS = 'has-expanded-drawer'; - var EXP_DRAWER_CLS = 'expanded'; - - ns.SettingsController = function (piskelController) { - this.piskelController = piskelController; - this.drawerContainer = document.getElementById('drawer-container'); - this.settingsContainer = $('[data-pskl-controller=settings]'); - this.isExpanded = false; - this.currentSetting = null; - }; - - /** - * @public - */ - ns.SettingsController.prototype.init = function() { - $('[data-setting]').click(this.onSettingIconClick.bind(this)); - $('body').click(this.onBodyClick.bind(this)); - $.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this)); - }; - - ns.SettingsController.prototype.onSettingIconClick = function (evt) { - var el = evt.originalEvent.currentTarget; - var setting = el.getAttribute('data-setting'); - if (this.currentSetting != setting) { - this.loadSetting(setting); - } else { - this.closeDrawer(); - } - evt.originalEvent.stopPropagation(); - evt.originalEvent.preventDefault(); - }; - - ns.SettingsController.prototype.onBodyClick = function (evt) { - var target = evt.target; - - var isInDrawerContainer = pskl.utils.Dom.isParent(target, this.drawerContainer); - var isInSettingsIcon = target.getAttribute('data-setting'); - var isInSettingsContainer = isInDrawerContainer || isInSettingsIcon; - - if (this.isExpanded && !isInSettingsContainer) { - this.closeDrawer(); - } - }; - - ns.SettingsController.prototype.loadSetting = function (setting) { - this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template); - (new settings[setting].controller(this.piskelController)).init(); - - this.settingsContainer.addClass(EXP_DRAWER_CLS); - - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - $('[data-setting='+setting+']').addClass(SEL_SETTING_CLS); - - this.isExpanded = true; - this.currentSetting = setting; - }; - - ns.SettingsController.prototype.closeDrawer = function () { - this.settingsContainer.removeClass(EXP_DRAWER_CLS); - $('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS); - - this.isExpanded = false; - this.currentSetting = null; - - document.activeElement.blur(); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.AbstractDialogController = function () {}; - - - ns.AbstractDialogController.prototype.init = function () { - this.closeButton = document.querySelector('.dialog-close'); - this.closeButton.addEventListener('click', this.closeDialog.bind(this)); - }; - - ns.AbstractDialogController.prototype.destroy = function () {}; - - ns.AbstractDialogController.prototype.closeDialog = function () { - this.destroy(); - $.publish(Events.DIALOG_HIDE); - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteController = function (piskelController) { - this.paletteService = pskl.app.paletteService; - this.paletteImportService = pskl.app.paletteImportService; - this.selectedIndex = -1; - }; - - pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - - ns.CreatePaletteController.prototype.init = function (paletteId) { - this.superclass.init.call(this); - - this.colorsList = document.querySelector('.colors-list'); - this.colorPreviewEl = document.querySelector('.color-preview'); - this.hiddenFileInput = document.querySelector('.create-palette-import-input'); - this.nameInput = document.querySelector('input[name="palette-name"]'); - - var submitButton = document.querySelector('.create-palette-submit'); - var cancelButton = document.querySelector('.create-palette-cancel'); - var importFileButton = document.querySelector('.create-palette-import-button'); - - this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); - this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - - submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this)); - cancelButton.addEventListener('click', this.closeDialog.bind(this)); - importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); - - var colorPickerContainer = document.querySelector('.color-picker-container'); - this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); - this.hslRgbColorPicker.init(); - - var palette; - if (paletteId) { - var paletteObject = this.paletteService.getPaletteById(paletteId); - palette = pskl.model.Palette.fromObject(paletteObject); - } else { - palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), 'New palette', []); - } - - this.setPalette_(palette); - }; - - ns.CreatePaletteController.prototype.setPalette_ = function (palette) { - this.palette = palette; - this.nameInput.value = pskl.utils.unescapeHtml(this.palette.name); - this.refresh_(); - }; - - ns.CreatePaletteController.prototype.destroy = function () { - this.colorsList = null; - this.colorPreviewEl = null; - this.nameInput = null; - }; - - ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { - var rgbColor = color.toRgbString(); - this.colorPreviewEl.style.background = rgbColor; - if (this.palette) { - this.palette.set(this.selectedIndex, rgbColor); - this.refreshColorElement_(this.selectedIndex); - } - }; - - /** - * Lightweight refresh only changing the color of one element of the palette color list - */ - ns.CreatePaletteController.prototype.refreshColorElement_ = function (index) { - var color = this.palette.get(this.selectedIndex); - var element = document.querySelector('[data-palette-index="'+index+'"]'); - if (element) { - element.style.background = color; - element.classList.toggle('light-color', this.isLight_(color)); - } - }; - - ns.CreatePaletteController.prototype.onColorContainerClick_ = function (evt) { - var target = evt.target; - if (target.classList.contains('create-palette-color')) { - this.onPaletteColorClick_(evt, target); - } else if (target.classList.contains('create-palette-new-color')) { - this.onNewColorClick_(evt, target); - } else if (target.classList.contains('create-palette-remove-color')) { - this.onRemoveColorClick_(evt, target); - } - this.refresh_(); - }; - - ns.CreatePaletteController.prototype.onPaletteColorClick_ = function (evt, target) { - var index = parseInt(target.dataset.paletteIndex,10); - this.selectColor_(index); - }; - - ns.CreatePaletteController.prototype.onRemoveColorClick_ = function (evt, target) { - var colorElement = target.parentNode; - var index = parseInt(colorElement.dataset.paletteIndex,10); - this.removeColor_(index); - }; - - ns.CreatePaletteController.prototype.onNewColorClick_ = function (evt, target) { - var newColor = this.palette.get(this.selectedIndex) || '#000000'; - this.palette.add(newColor); - this.selectColor_(this.palette.size()-1); - }; - - ns.CreatePaletteController.prototype.onSubmitButtonClick_ = function (evt) { - this.paletteService.savePalette(this.palette); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { - this.hiddenFileInput.click(); - }; - - ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) { - var files = this.hiddenFileInput.files; - if (files.length == 1) { - this.paletteImportService.read(files[0], this.setPalette_.bind(this)); - } - }; - - ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { - this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); - }; - - ns.CreatePaletteController.prototype.selectColor_ = function (index) { - this.selectedIndex = index; - this.hslRgbColorPicker.setColor(this.palette.get(index)); - }; - - ns.CreatePaletteController.prototype.removeColor_ = function (index) { - this.palette.removeAt(index); - this.refresh_(); - }; - - ns.CreatePaletteController.prototype.refresh_ = function () { - var html = ""; - var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.colors; - - colors.forEach(function (color, index) { - var isSelected = (index === this.selectedIndex); - - html += pskl.utils.Template.replace(tpl, { - color:color, index:index, - ':selected':isSelected, - ':light-color':this.isLight_(color) - }); - }.bind(this)); - - html += '
      • +
      • '; - - this.colorsList.innerHTML = html; - - $('.colors-list').sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onDrop_.bind(this), - items: '.create-palette-color' - }); - }; - - ns.CreatePaletteController.prototype.isLight_ = function (color) { - var rgb = window.tinycolor(color).toRgb(); - return rgb.r+rgb.b+rgb.g > 128*3; - }; - - - ns.CreatePaletteController.prototype.onDrop_ = function (evt, drop) { - var colorElement = drop.item.get(0); - - var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); - var newIndex = $('.create-palette-color').index(drop.item); - this.palette.move(oldIndex, newIndex); - - this.selectedIndex = newIndex; - - this.refresh_(); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - var PREVIEW_HEIGHT = 60; - - ns.ImportImageController = function (piskelController) { - this.importedImage_ = null; - this.file_ = null; - }; - - pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController); - - ns.ImportImageController.prototype.init = function (file) { - this.superclass.init.call(this); - - this.file_ = file; - - this.importPreview = $('.import-section-preview'); - - this.fileNameContainer = $('.import-image-file-name'); - - this.resizeWidth = $('[name=resize-width]'); - this.resizeHeight = $('[name=resize-height]'); - this.smoothResize = $('[name=smooth-resize-checkbox]'); - - this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width')); - this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height')); - - this.importImageForm = $('[name=import-image-form]'); - this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); - - pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this)); - }; - - ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { - evt.originalEvent.preventDefault(); - this.importImageToPiskel_(); - }; - - ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) { - if (this.importedImage_) { - this.synchronizeResizeFields_(evt.target.value, from); - } - }; - - ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) { - value = parseInt(value, 10); - if (isNaN(value)) { - value = 0; - } - var height = this.importedImage_.height, width = this.importedImage_.width; - if (from === 'width') { - this.resizeHeight.val(Math.round(value * height / width)); - } else { - this.resizeWidth.val(Math.round(value * width / height)); - } - }; - - ns.ImportImageController.prototype.onImageLoaded_ = function (image) { - this.importedImage_ = image; - - var w = this.importedImage_.width, - h = this.importedImage_.height; - - // FIXME : We remove the onload callback here because JsGif will insert - // the image again and we want to avoid retriggering the image onload - this.importedImage_.onload = function () {}; - - var fileName = this.extractFileNameFromPath_(this.file_.name); - this.fileNameContainer.html(fileName); - - this.resizeWidth.val(w); - this.resizeHeight.val(h); - - this.importPreview.width('auto'); - this.importPreview.html(''); - this.importPreview.append(this.createImagePreview_()); - }; - - ns.ImportImageController.prototype.createImagePreview_ = function () { - var image = document.createElement('IMG'); - image.src = this.importedImage_.src; - image.setAttribute('height', PREVIEW_HEIGHT); - return image; - }; - - ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) { - var parts = []; - if (path.indexOf('/') !== -1) { - parts = path.split('/'); - } else if (path.indexOf('\\') !== -1) { - parts = path.split('\\'); - } else { - parts = [path]; - } - return parts[parts.length-1]; - }; - - ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { - if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - gifLoader.load({ - success : function(){ - var images = gifLoader.getFrames().map(function (frame) { - return pskl.CanvasUtils.createFromImageData(frame.data); - }); - this.createPiskelFromImages_(images); - this.closeDialog(); - }.bind(this), - error : function () { - this.createPiskelFromImages_([image]); - this.closeDialog(); - }.bind(this) - }); - - } - } - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images) { - var w = this.resizeWidth.val(); - var h = this.resizeHeight.val(); - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) { - var frames = this.createFramesFromImages_(images); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.BrowseLocalController = function (piskelController) { - }; - - pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController); - - ns.BrowseLocalController.prototype.init = function () { - this.superclass.init.call(this); - - this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); - - this.service_ = pskl.app.localStorageService; - this.piskelList = $('.local-piskel-list'); - this.prevSessionContainer = $('.previous-session'); - - this.fillLocalPiskelsList_(); - - this.piskelList.click(this.onPiskelsListClick_.bind(this)); - }; - - ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) { - var action = evt.target.getAttribute('data-action'); - var name = evt.target.getAttribute('data-name'); - if (action === 'load') { - if (window.confirm('This will erase your current piskel. Continue ?')) { - this.service_.load(name); - this.closeDialog(); - } - } else if (action === 'delete') { - if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { - this.service_.remove(name); - this.fillLocalPiskelsList_(); - } - } - }; - - ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () { - var html = ""; - var keys = this.service_.getKeys(); - - keys.sort(function (k1, k2) { - if (k1.date < k2.date) {return 1;} - if (k1.date > k2.date) {return -1;} - return 0; - }); - - keys.forEach((function (key) { - var date = pskl.utils.DateUtils.format(key.date, "{{Y}}/{{M}}/{{D}} {{H}}:{{m}}"); - html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date}); - }).bind(this)); - - var tableBody_ = this.piskelList.get(0).tBodies[0]; - tableBody_.innerHTML = html; - }; -})();;(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var dialogs = { - 'create-palette' : { - template : 'templates/dialogs/create-palette.html', - controller : ns.CreatePaletteController - }, - 'browse-local' : { - template : 'templates/dialogs/browse-local.html', - controller : ns.BrowseLocalController - }, - 'import-image' : { - template : 'templates/dialogs/import-image.html', - controller : ns.ImportImageController - } - }; - - ns.DialogsController = function (piskelController) { - this.piskelController = piskelController; - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.init = function () { - this.dialogContainer_ = document.getElementById('dialog-container'); - this.dialogWrapper_ = document.getElementById('dialog-container-wrapper'); - $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); - $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palettes')); - this.dialogWrapper_.classList.add('animated'); - }; - - ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) { - var dialogId, initArgs; - if (typeof args === 'string') { - dialogId = args; - } else { - dialogId = args.dialogId; - initArgs = args.initArgs; - } - if (!this.isDisplayed()) { - var config = dialogs[dialogId]; - if (config) { - this.dialogContainer_.classList.add(dialogId); - this.dialogContainer_.innerHTML = pskl.utils.Template.get(config.template); - - var controller = new config.controller(this.piskelController); - controller.init(initArgs); - - this.showDialogWrapper_(); - this.currentDialog_ = { - id : dialogId, - controller : controller - }; - } else { - console.error('Could not find dialog configuration for dialogId : ' + dialogId); - } - } - }; - - ns.DialogsController.prototype.onDialogHideEvent_ = function () { - this.hideDialog(); - }; - - ns.DialogsController.prototype.showDialogWrapper_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideDialog.bind(this)); - this.dialogWrapper_.classList.add('show'); - }; - - ns.DialogsController.prototype.hideDialog = function () { - var currentDialog = this.currentDialog_; - if (currentDialog) { - currentDialog.controller.destroy(); - var dialogId = this.currentDialog_.id; - window.setTimeout(function () { - this.dialogContainer_.classList.remove(dialogId); - }.bind(this), 800); - } - - this.hideDialogWrapper_(); - this.currentDialog_ = null; - }; - - ns.DialogsController.prototype.hideDialogWrapper_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.dialogWrapper_.classList.remove('show'); - }; - - ns.DialogsController.prototype.isDisplayed = function () { - return this.currentDialog_ !== null; - }; - -})();;(function () { - var ns = $.namespace('pskl.controller.widgets'); - - ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { - this.container = container; - this.colorUpdatedCallback = colorUpdatedCallback; - this.lastInputTimestamp_ = 0; - }; - - ns.HslRgbColorPicker.prototype.init = function () { - var isChromeOrFirefox = pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isFirefox; - var changeEvent = isChromeOrFirefox ? 'input' : 'change'; - this.container.addEventListener(changeEvent, this.onPickerChange_.bind(this)); - - this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); - - $(this.spectrumEl).spectrum({ - flat: true, - showInput: true, - showButtons: false, - move : this.setColor.bind(this), - change : this.setColor.bind(this) - }); - - this.setColor("#000000"); - }; - - - ns.HslRgbColorPicker.prototype.onPickerChange_ = function (evt) { - var target = evt.target; - - var model = target.dataset.model; - var dimension = target.dataset.dimension; - - var value = parseInt(target.value, 10); - if (dimension === 'v' || dimension === 's') { - value = value/100; - } - - var color; - if (model === 'rgb') { - color = this.tinyColor.toRgb(); - } else if (model === 'hsv') { - color = this.hsvColor; - } - - if (isNaN(value)) { - value = color[dimension]; - } else { - color[dimension] = value; - } - - this.setColor(color); - }; - - ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.colorUpdatedCallback(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.HslRgbColorPicker.prototype.updateInputs = function () { - var inputs = this.container.querySelectorAll('input'); - var rgb = this.tinyColor.toRgb(); - - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - if (model === 'rgb') { - input.value = rgb[dimension]; - } else if (model === 'hsv') { - var value = this.hsvColor[dimension]; - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - input.value = Math.round(value); - } - - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - var colors = this.getSliderBackgroundColors_(model, dimension); - slider.style.backgroundImage = "linear-gradient(to right, " + colors.start + " 0, " + colors.end + " 100%)"; - } - }; - - ns.HslRgbColorPicker.prototype.getSliderBackgroundColors_ = function (model, dimension) { - var start, end; - if (model === 'hsv') { - start = JSON.parse(JSON.stringify(this.hsvColor)); - start[dimension] = 0; - - end = JSON.parse(JSON.stringify(this.hsvColor)); - end[dimension] = 1; - } else { - start = this.tinyColor.toRgb(); - start[dimension] = 0; - - end = this.tinyColor.toRgb(); - end[dimension] = 255; - } - - return { - start : window.tinycolor(start).toRgbString(), - end : window.tinycolor(end).toRgbString() - }; - }; - - ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } else { - return window.tinycolor(JSON.parse(JSON.stringify(color))); - } - }; - - ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : Math.max(0, Math.min(359, color.h)), - s : Math.max(0, Math.min(1, color.s)), - v : Math.max(0, Math.min(1, color.v)) - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - -})();;(function () { - var ns = $.namespace("pskl.service"); - - ns.LocalStorageService = function (piskelController) { - - if(piskelController === undefined) { - throw "Bad LocalStorageService initialization: "; - } - this.piskelController = piskelController; - }; - - ns.LocalStorageService.prototype.init = function() {}; - - ns.LocalStorageService.prototype.save = function(name, description, piskel) { - this.removeFromKeys_(name); - this.addToKeys_(name, description, Date.now()); - window.localStorage.setItem('piskel.' + name, piskel); - }; - - ns.LocalStorageService.prototype.load = function(name) { - var piskelString = this.getPiskel(name); - var key = this.getKey_(name); - var serializedPiskel = JSON.parse(piskelString); - // FIXME : should be moved to deserializer - // Deserializer should call callback with descriptor + fps information - var fps = serializedPiskel.piskel.fps; - var description = serializedPiskel.piskel.description; - - pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - }); - }; - - ns.LocalStorageService.prototype.remove = function(name) { - this.removeFromKeys_(name); - window.localStorage.removeItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.saveKeys_ = function(keys) { - window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); - }; - - ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { - var keys = this.getKeys(); - var otherKeys = keys.filter(function (key) { - return key.name !== name; - }); - - this.saveKeys_(otherKeys); - }; - - ns.LocalStorageService.prototype.getKey_ = function(name) { - var matches = this.getKeys().filter(function (key) { - return key.name === name; - }); - if (matches.length > 0) { - return matches[0]; - } else { - return null; - } - }; - - ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { - var keys = this.getKeys(); - keys.push({ - name : name, - description : description, - date : date - }); - this.saveKeys_(keys); - }; - - ns.LocalStorageService.prototype.getPiskel = function(name) { - return window.localStorage.getItem('piskel.' + name); - }; - - ns.LocalStorageService.prototype.getKeys = function(name) { - var keysString = window.localStorage.getItem('piskel.keys'); - return JSON.parse(keysString) || []; - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.GithubStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.GithubStorageService.prototype.init = function () {}; - - ns.GithubStorageService.prototype.store = function (callbacks) { - throw "Github save is no longer available. Use local save instead"; - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.AppEngineStorageService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.AppEngineStorageService.prototype.init = function () {}; - - ns.AppEngineStorageService.prototype.store = function (callbacks) { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - - var data = { - framesheet : this.piskelController.serialize(), - fps : this.piskelController.getFPS(), - name : descriptor.name, - description : descriptor.description, - frames : this.piskelController.getFrameCount(), - first_frame_as_png : pskl.app.getFirstFrameAsPng(), - framesheet_as_png : pskl.app.getFramesheetAsPng() - }; - - if (descriptor.isPublic) { - data['public'] = true; - } - - var success = function () { - callbacks.success(); - callbacks.after(); - }; - - var error = function (response) { - callbacks.error(response.status); - callbacks.after(); - }; - - pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE, data, success, error); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - var BACKUP_INTERVAL = 1000 * 60; - - ns.BackupService = function (piskelController) { - this.piskelController = piskelController; - this.lastHash = null; - }; - - ns.BackupService.prototype.init = function () { - var previousPiskel = window.localStorage.getItem('bkp.next.piskel'); - var previousInfo = window.localStorage.getItem('bkp.next.info'); - if (previousPiskel && previousInfo) { - window.localStorage.setItem('bkp.prev.piskel', previousPiskel); - window.localStorage.setItem('bkp.prev.info', previousInfo); - } - window.setInterval(this.backup.bind(this), BACKUP_INTERVAL); - }; - - ns.BackupService.prototype.backup = function () { - var piskel = this.piskelController.getPiskel(); - var descriptor = piskel.getDescriptor(); - var hash = piskel.getHash(); - var info = { - name : descriptor.name, - description : descriptor.info, - fps : this.piskelController.getFPS(), - date : Date.now(), - hash : hash - }; - - // Do not save an unchanged piskel - if (hash !== this.lastHash) { - this.lastHash = hash; - window.localStorage.setItem('bkp.next.piskel', this.piskelController.serialize()); - window.localStorage.setItem('bkp.next.info', JSON.stringify(info)); - } - }; - - ns.BackupService.prototype.getPreviousPiskelInfo = function () { - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - if (previousInfo) { - return JSON.parse(previousInfo); - } - }; - - - ns.BackupService.prototype.load = function() { - - var previousPiskel = window.localStorage.getItem('bkp.prev.piskel'); - var previousInfo = window.localStorage.getItem('bkp.prev.info'); - previousPiskel = JSON.parse(previousPiskel); - previousInfo = JSON.parse(previousInfo); - - pskl.utils.serialization.Deserializer.deserialize(previousPiskel, function (piskel) { - piskel.setDescriptor(new pskl.model.piskel.Descriptor(previousInfo.name, previousInfo.description, true)); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(previousInfo.fps); - }); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.BeforeUnloadService = function (piskelController) { - this.piskelController = piskelController; - }; - - - ns.BeforeUnloadService.prototype.init = function () { - window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); - }; - - ns.BeforeUnloadService.prototype.onBeforeUnload = function (evt) { - pskl.app.backupService.backup(); - if (pskl.app.savedStatusService.isDirty()) { - var confirmationMessage = "Your Piskel seems to have unsaved changes"; - - (evt || window.event).returnValue = confirmationMessage; - return confirmationMessage; - } - }; - -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.HistoryService = function (piskelController, shortcutService, deserializer) { - this.piskelController = piskelController || pskl.app.piskelController; - this.shortcutService = shortcutService || pskl.app.shortcutService; - this.deserializer = deserializer || pskl.utils.serialization.Deserializer; - - this.stateQueue = []; - this.currentIndex = -1; - - this.lastLoadState = -1; - - this.saveNextAsSnapshot = false; - }; - - ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; - ns.HistoryService.REPLAY = 'REPLAY'; - ns.HistoryService.SNAPSHOT_PERIOD = 50; - ns.HistoryService.LOAD_STATE_INTERVAL = 50; - /** - * This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command. - * Don't store snapshots for such events. - */ - ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT'; - - ns.HistoryService.prototype.init = function () { - $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this)); - - this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); - this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); - - this.saveState({ - type : ns.HistoryService.SNAPSHOT - }); - }; - - ns.HistoryService.prototype.onSaveStateEvent = function (evt, stateInfo) { - this.saveState(stateInfo); - }; - - ns.HistoryService.prototype.saveState = function (stateInfo) { - this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1); - this.currentIndex = this.currentIndex + 1; - - var state = { - action : stateInfo, - frameIndex : this.piskelController.currentFrameIndex, - layerIndex : this.piskelController.currentLayerIndex - }; - - var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT; - var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT; - var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot; - if (isNoSnapshot && isAtAutoSnapshotInterval) { - this.saveNextAsSnapshot = true; - } else if (isSnapshot || isAtAutoSnapshotInterval) { - state.piskel = this.piskelController.serialize(true); - this.saveNextAsSnapshot = false; - } - - this.stateQueue.push(state); - }; - - ns.HistoryService.prototype.undo = function () { - this.loadState(this.currentIndex - 1); - }; - - ns.HistoryService.prototype.redo = function () { - this.loadState(this.currentIndex + 1); - }; - - ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { - var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL; - var indexInRange = index >= 0 && index < this.stateQueue.length; - return timeOk && indexInRange; - }; - - ns.HistoryService.prototype.getPreviousSnapshotIndex_ = function (index) { - while (this.stateQueue[index] && !this.stateQueue[index].piskel) { - index = index - 1; - } - return index; - }; - - ns.HistoryService.prototype.loadState = function (index) { - try { - if (this.isLoadStateAllowed_(index)) { - this.lastLoadState = Date.now(); - - var snapshotIndex = this.getPreviousSnapshotIndex_(index); - if (snapshotIndex < 0) { - throw 'Could not find previous SNAPSHOT saved in history stateQueue'; - } - var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); - var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); - this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); - } - } catch (e) { - window.console.error("[CRITICAL ERROR] : Unable to load a history state."); - if (typeof e === "string") { - window.console.error(e); - } else { - window.console.error(e.message); - window.console.error(e.stack); - } - this.stateQueue = []; - this.currentIndex = -1; - } - }; - - ns.HistoryService.prototype.getSnapshotFromState_ = function (stateIndex) { - var state = this.stateQueue[stateIndex]; - var piskelSnapshot = state.piskel; - - // If the snapshot is stringified, parse it and backup the result for faster access next time - // FIXME : Memory consumption might go crazy if we keep unpacking big piskels indefinitely - // ==> should ensure I remove some of them :) - if (typeof piskelSnapshot === "string") { - piskelSnapshot = JSON.parse(piskelSnapshot); - state.piskel = piskelSnapshot; - } - - return piskelSnapshot; - }; - - ns.HistoryService.prototype.onPiskelLoaded_ = function (index, snapshotIndex, piskel) { - var originalSize = this.getPiskelSize_(); - piskel.setDescriptor(this.piskelController.piskel.getDescriptor()); - this.piskelController.setPiskel(piskel); - - for (var i = snapshotIndex + 1 ; i <= index ; i++) { - var state = this.stateQueue[i]; - this.setupState(state); - this.replayState(state); - } - - // Should only do this when going backwards - var lastState = this.stateQueue[index+1]; - if (lastState) { - this.setupState(lastState); - } - - this.currentIndex = index; - $.publish(Events.PISKEL_RESET); - if (originalSize !== this.getPiskelSize_()) { - $.publish(Events.FRAME_SIZE_CHANGED); - } - }; - - ns.HistoryService.prototype.getPiskelSize_ = function () { - return this.piskelController.getWidth() + 'x' + this.piskelController.getHeight(); - }; - - ns.HistoryService.prototype.setupState = function (state) { - this.piskelController.setCurrentFrameIndex(state.frameIndex); - this.piskelController.setCurrentLayerIndex(state.layerIndex); - }; - - ns.HistoryService.prototype.replayState = function (state) { - var action = state.action; - var type = action.type; - var layer = this.piskelController.getLayerAt(state.layerIndex); - var frame = layer.getFrameAt(state.frameIndex); - action.scope.replay(frame, action.replay); - }; - -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteService = function () { - this.palettes = []; - this.localStorageService = window.localStorage; - }; - - ns.PaletteService.prototype.getPalettes = function () { - var palettesString = this.localStorageService.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; - - ns.PaletteService.prototype.getPaletteById = function (paletteId) { - var palettes = this.getPalettes(); - return this.findPaletteInArray_(paletteId, palettes); - }; - - ns.PaletteService.prototype.savePalette = function (palette) { - var palettes = this.getPalettes(); - var existingPalette = this.findPaletteInArray_(palette.id, palettes); - if (existingPalette) { - var currentIndex = palettes.indexOf(existingPalette); - palettes.splice(currentIndex, 1, palette); - } else { - palettes.push(palette); - } - - this.savePalettes_(palettes); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteService.prototype.deletePaletteById = function (id) { - var palettes = this.getPalettes(); - var filteredPalettes = palettes.filter(function (palette) { - return palette.id !== id; - }); - - this.savePalettes_(filteredPalettes); - }; - - ns.PaletteService.prototype.savePalettes_ = function (palettes) { - this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var supportedFileFormats = ['gpl']; - - ns.PaletteImportService = function () {}; - - ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader; - if (this.isImage_(file)){ - reader = new ns.PaletteImageReader(file, onSuccess, onError); - } else if (this.isSupportedFormat_(file)) { - reader = this.getFileReader_(file, onSuccess, onError); - } - - if (reader) { - reader.read(); - } else { - throw 'Could not find reader for file : ' + file.name; - } - }; - - ns.PaletteImportService.prototype.isImage_ = function (file) { - return file.type.indexOf('image') === 0; - }; - - ns.PaletteImportService.prototype.getFileReader_ = function (file, onSuccess, onError) { - var extension = this.getExtension_(file); - if (extension === 'gpl') { - return new ns.PaletteGplReader(file, onSuccess, onError); - } - }; - - ns.PaletteImportService.prototype.isSupportedFormat_ = function (file) { - var extension = this.getExtension_(file); - return supportedFileFormats.indexOf(extension) != -1; - }; - - ns.PaletteImportService.prototype.getExtension_ = function (file) { - var parts = file.name.split('.'); - return parts[parts.length-1]; - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - var RE_COLOR_LINE = /^(\d{1,3}\s+)(\d{1,3}\s+)(\d{1,3}\s+)/; - var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; - - ns.PaletteGplReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - }; - - ns.PaletteGplReader.prototype.read = function () { - pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this)); - }; - - ns.PaletteGplReader.prototype.onFileLoaded_ = function (content) { - var text = pskl.utils.Base64.toText(content); - var lines = text.match(/[^\r\n]+/g); - - var name = lines.map(function (l) { - var matches = l.match(RE_EXTRACT_NAME); - return matches ? matches[1] : ''; - }).join(''); - - var colorLines = lines.filter(function (l) { - return RE_COLOR_LINE.test(l); - }); - - var colors = colorLines.map(function (l) { - var matches = l.match(RE_COLOR_LINE); - var color = window.tinycolor({ - r : parseInt(matches[1], 10), - g : parseInt(matches[2], 10), - b : parseInt(matches[3], 10) - }); - - return color.toRgbString(); - }); - - if (name && colors.length) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, name, colors); - this.onSuccess(palette); - } else { - this.onError(); - } - - }; -})();;(function () { - var ns = $.namespace('pskl.service.palette'); - - ns.PaletteImageReader = function (file, onSuccess, onError) { - this.file = file; - this.onSuccess = onSuccess; - this.onError = onError; - }; - - ns.PaletteImageReader.prototype.read = function () { - pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this)); - }; - - ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) { - var frame = pskl.utils.FrameUtils.createFromImage(image); - var colorsMap = {}; - frame.forEachPixel(function (color, x, y) { - colorsMap[color] = true; - }); - - delete colorsMap[Constants.TRANSPARENT_COLOR]; - - var colors = Object.keys(colorsMap); - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', colors); - - this.onSuccess(palette); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.SavedStatusService = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SavedStatusService.prototype.init = function () { - $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); - - $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); - }; - - ns.SavedStatusService.prototype.onPiskelReset = function () { - var piskel = this.piskelController.getPiskel(); - // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored - // putting a firstResetDone flag as a nasty workaround for this - if (piskel.firstResetDone_) { - this.updateDirtyStatus(true); - } else { - piskel.firstResetDone_ = true; - } - }; - - ns.SavedStatusService.prototype.onToolReleased = function () { - this.updateDirtyStatus(true); - }; - - ns.SavedStatusService.prototype.onPiskelSaved = function () { - this.updateDirtyStatus(false); - }; - - ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { - var piskel = this.piskelController.getPiskel(); - if (piskel.isDirty_ !== status) { - // Redraw piskel name only if dirty status actually changed - piskel.isDirty_ = status; - this.updatePiskelName(); - } - }; - - ns.SavedStatusService.prototype.updatePiskelName = function () { - var piskel = this.piskelController.getPiskel(); - var name = piskel.getDescriptor().name; - if (piskel.isDirty_) { - $('.piskel-name').html(name + ' *'); - } else { - $('.piskel-name').html(name); - } - }; - - ns.SavedStatusService.prototype.isDirty = function (evt) { - var piskel = this.piskelController.getPiskel(); - return piskel.isDirty_; - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.ShortcutService = function () { - this.shortcuts_ = {}; - }; - - /** - * @public - */ - ns.ShortcutService.prototype.init = function() { - $(document.body).keydown($.proxy(this.onKeyUp_, this)); - }; - - /** - * Add a keyboard shortcut - * @param {String} rawKey (case insensitive) key can be a meta (optional) + [a-z0-9] or - * a special key (check list of supported keys in KeycodeTranslator) - * eg. 'ctrl+A', 'del' - * @param {Function} callback should return true to let the original event perform its default action - */ - ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - if (this.shortcuts_[key][meta]) { - var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key; - console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered'); - } else { - this.shortcuts_[key][meta] = callback; - } - }; - - ns.ShortcutService.prototype.removeShortcut = function (rawKey) { - var parsedKey = this.parseKey_(rawKey.toLowerCase()); - - var key = parsedKey.key, - meta = parsedKey.meta; - - this.shortcuts_[key] = this.shortcuts_[key] || {}; - - this.shortcuts_[key][meta] = null; - }; - - ns.ShortcutService.prototype.parseKey_ = function (key) { - var meta = this.getMetaKey_({ - alt : key.indexOf('alt+') != -1, - shift : key.indexOf('shift+') != -1, - ctrl : key.indexOf('ctrl+') != -1 - }); - - var parts = key.split(/\+(?!$)/); - key = parts[parts.length-1]; - return {meta : meta, key : key}; - }; - - ns.ShortcutService.prototype.getMetaKey_ = function (meta) { - var keyBuffer = []; - ['alt', 'ctrl', 'shift'].forEach(function (metaKey) { - if (meta[metaKey]) { - keyBuffer.push(metaKey); - } - }); - - if (keyBuffer.length > 0) { - return keyBuffer.join('+'); - } else { - return 'normal'; - } - }; - /** - * @private - */ - ns.ShortcutService.prototype.onKeyUp_ = function(evt) { - if (!this.isInInput_(evt)) { - // jquery names FTW ... - var keycode = evt.which; - var targetTagName = evt.target.nodeName.toUpperCase(); - var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode); - - var keyShortcuts = this.shortcuts_[charkey]; - if(keyShortcuts) { - var meta = this.getMetaKey_({ - alt : this.isAltKeyPressed_(evt), - shift : this.isShiftKeyPressed_(evt), - ctrl : this.isCtrlKeyPressed_(evt) - }); - var cb = keyShortcuts[meta]; - - if(cb) { - var bubble = cb(charkey); - if (bubble !== true) { - evt.preventDefault(); - } - } - } - } - }; - - ns.ShortcutService.prototype.isInInput_ = function (evt) { - var targetTagName = evt.target.nodeName.toUpperCase(); - return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA'; - }; - - ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) { - return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey; - }; - - ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) { - return evt.shiftKey; - }; - - ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) { - return evt.altKey; - }; -})();;(function () { - var specialKeys = { - 191 : "?", - 8 : "back", - 27 : "esc", - 38 : "up", - 40 : "down", - 46 : "del", - 189 : "-", - 187 : "+" - }; - - var ns = $.namespace('pskl.service.keyboard'); - - ns.KeycodeTranslator= { - toChar : function (keycode) { - if (keycode >= 48 && keycode <= 57) { - // key is 0-9 - return (keycode - 48) + ""; - } else if (keycode >= 65 && keycode <= 90) { - // key is a-z, use base 36 to get the string representation - return (keycode - 65 + 10).toString(36); - } else { - return specialKeys[keycode]; - } - } - }; -})();;(function () { - var ns = $.namespace('pskl.service.keyboard'); - - ns.CheatsheetService = function () { - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.init = function () { - this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper'); - if (!this.cheatsheetEl_) { - throw 'cheatsheetEl_ DOM element could not be retrieved'; - } - this.initMarkup_(); - pskl.app.shortcutService.addShortcut('shift+?', this.toggleCheatsheet_.bind(this)); - pskl.app.shortcutService.addShortcut('?', this.toggleCheatsheet_.bind(this)); - - var link = $('.cheatsheet-link'); - link.click(this.toggleCheatsheet_.bind(this)); - - $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); - $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); - }; - - ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } else { - this.showCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.onEscape_ = function () { - if (this.isDisplayed_) { - this.hideCheatsheet_(); - } - }; - - ns.CheatsheetService.prototype.showCheatsheet_ = function () { - pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this)); - this.cheatsheetEl_.style.display = 'block'; - this.isDisplayed_ = true; - }; - - - ns.CheatsheetService.prototype.hideCheatsheet_ = function () { - pskl.app.shortcutService.removeShortcut('ESC'); - this.cheatsheetEl_.style.display = 'none'; - this.isDisplayed_ = false; - }; - - ns.CheatsheetService.prototype.initMarkup_ = function () { - this.initMarkupForTools_(); - this.initMarkupForMisc_(); - this.initMarkupForSelection_(); - }; - - ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) { - if (pskl.utils.UserAgent.isMac) { - shortcut = shortcut.replace('ctrl', 'cmd'); - } - return { - 'shortcut' : shortcut, - 'description' : description, - 'icon' : icon - }; - }; - - ns.CheatsheetService.prototype.getDomFromDescriptor_ = function (descriptor) { - var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template'); - var markup = pskl.utils.Template.replace(shortcutTemplate, { - shortcutIcon : descriptor.icon, - shortcutDescription : descriptor.description, - shortcutKey : descriptor.shortcut - }); - - return pskl.utils.Template.createFromHTML(markup); - }; - - ns.CheatsheetService.prototype.initMarkupAbstract_ = function (descriptors, containerSelector) { - var container = $(containerSelector, this.cheatsheetEl_).get(0); - for (var i = 0 ; i < descriptors.length ; i++) { - var descriptor = descriptors[i]; - var shortcutEl = this.getDomFromDescriptor_(descriptor); - container.appendChild(shortcutEl); - } - }; - - ns.CheatsheetService.prototype.initMarkupForTools_ = function () { - var descriptors = pskl.app.toolController.tools.map(function (tool) { - return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId); - }.bind(this)); - - this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForMisc_ = function () { - var descriptors = [ - this.toDescriptor_('0', 'Reset zoom level'), - this.toDescriptor_('+/-', 'Zoom in/Zoom out'), - this.toDescriptor_('X', 'Swap primary/secondary colors'), - this.toDescriptor_('D', 'Reset default colors'), - this.toDescriptor_('ctrl + Z', 'Undo'), - this.toDescriptor_('ctrl + Y', 'Redo'), - this.toDescriptor_('↑', 'Select previous frame'), /* ASCII for up-arrow */ - this.toDescriptor_('↓', 'Select next frame'), /* ASCII for down-arrow */ - this.toDescriptor_('N', 'Create new frame'), - this.toDescriptor_('shift + N', 'Duplicate selected frame'), - this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Open the Palette Manager'), - this.toDescriptor_('alt + O', 'Toggle Onion Skin'), - this.toDescriptor_('alt + L', 'Toggle Layer Preview') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-misc-shortcuts'); - }; - - ns.CheatsheetService.prototype.initMarkupForSelection_ = function () { - var descriptors = [ - this.toDescriptor_('ctrl + X', 'Cut selection'), - this.toDescriptor_('ctrl + C', 'Copy selection'), - this.toDescriptor_('ctrl + V', 'Paste selection'), - this.toDescriptor_('del', 'Delete selection') - ]; - - this.initMarkupAbstract_(descriptors, '.cheatsheet-selection-shortcuts'); - }; - -})(); -;(function () { - var ns = $.namespace("pskl.service"); - ns.ImageUploadService = function () {}; - ns.ImageUploadService.prototype.init = function () {}; - - /** - * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; - * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) - * @param {Function} success success callback. 1st argument will be the uploaded image URL - * @param {Function} error error callback - */ - ns.ImageUploadService.prototype.upload = function (imageData, success, error) { - var data = { - data : imageData - }; - - var wrappedSuccess = function (response) { - success(Constants.IMAGE_SERVICE_GET_URL + response.responseText); - }; - - pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error); - }; -})(); -;(function () { - var ns = $.namespace('pskl.service'); - - ns.CurrentColorsService = function (piskelController) { - this.piskelController = piskelController; - this.currentColors = []; - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToColors_.bind(this)); - - this.framesColorsCache_ = {}; - }; - - ns.CurrentColorsService.prototype.init = function () { - $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); - $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); - }; - - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - - ns.CurrentColorsService.prototype.frameToColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - frameColors[color] = (frameColors[color] || 0) + 1; - }); - return frameColors; - }; - - - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { - var layers = this.piskelController.getLayers(); - var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); - var colors = {}; - frames.forEach(function (f) { - var frameColors = this.cachedFrameProcessor.get(f); - Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = (colors[color] || 0) + frameColors[color]; - }); - }.bind(this)); - - // Remove transparent color from used colors - delete colors[Constants.TRANSPARENT_COLOR]; - - // limit the array to the max colors to display - this.currentColors = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - - // sort by most frequent color - this.currentColors = this.currentColors.sort(function (c1, c2) { - return colors[c2] - colors[c1]; - }); - - // TODO : only fire if there was a change - $.publish(Events.CURRENT_COLORS_UPDATED, colors); - }; -})();;(function () { - var ns = $.namespace('pskl.service'); - - ns.FileDropperService = function (piskelController, drawingAreaContainer) { - this.piskelController = piskelController; - this.drawingAreaContainer = drawingAreaContainer; - this.dropPosition_ = null; - }; - - ns.FileDropperService.prototype.init = function () { - document.body.addEventListener('drop', this.onFileDrop.bind(this), false); - document.body.addEventListener('dragover', this.onFileDragOver.bind(this), false); - }; - - ns.FileDropperService.prototype.onFileDragOver = function (event) { - event.stopPropagation(); - event.preventDefault(); - event.dataTransfer.dropEffect = 'copy'; - }; - - ns.FileDropperService.prototype.onFileDrop = function (event) { - event.preventDefault(); - event.stopPropagation(); - - this.dropPosition_ = { - x : event.clientX, - y : event.clientY - }; - - var files = event.dataTransfer.files; - for (var i = 0; i < files.length ; i++) { - var file = files[i]; - var isImage = file.type.indexOf('image') === 0; - if (isImage) { - this.readImageFile_(file); - } else if (/\.piskel$/i.test(file.name)) { - pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); - } - } - }; - - ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { - if (window.confirm('This will replace your current animation')) { - piskel.setDescriptor(descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(fps); - } - }; - - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { - this.importedImage_ = new Image(); - this.importedImage_.onload = this.onImageLoaded_.bind(this); - this.importedImage_.src = imageSource; - }; - - ns.FileDropperService.prototype.onImageLoaded_ = function () { - var droppedFrame = pskl.utils.FrameUtils.createFromImage(this.importedImage_); - var currentFrame = this.piskelController.getCurrentFrame(); - - var dropCoordinates = this.adjustDropPosition_(this.dropPosition_, droppedFrame); - - currentFrame.forEachPixel(function (color, x, y) { - var fColor = droppedFrame.getPixel(x-dropCoordinates.x, y-dropCoordinates.y); - if (fColor && fColor != Constants.TRANSPARENT_COLOR) { - currentFrame.setPixel(x, y, fColor); - } - }); - - $.publish(Events.PISKEL_RESET); - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.SNAPSHOT - }); - }; - - ns.FileDropperService.prototype.adjustDropPosition_ = function (position, droppedFrame) { - var framePosition = pskl.app.drawingController.getSpriteCoordinates(position.x, position.y); - - var xCoord = framePosition.x - Math.floor(droppedFrame.width/2); - var yCoord = framePosition.y - Math.floor(droppedFrame.height/2); - - xCoord = Math.max(0, xCoord); - yCoord = Math.max(0, yCoord); - - var currentFrame = this.piskelController.getCurrentFrame(); - if (droppedFrame.width <= currentFrame.width) { - xCoord = Math.min(xCoord, currentFrame.width - droppedFrame.width); - } - - if (droppedFrame.height <= currentFrame.height) { - yCoord = Math.min(yCoord, currentFrame.height - droppedFrame.height); - } - - return { - x : xCoord, - y : yCoord - }; - }; - -})();;/** - * @provide pskl.drawingtools.BaseTool - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.drawingtools"); - - ns.BaseTool = function() { - this.toolId = "tool-base"; - }; - - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {}; - - ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION; - - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay, event) { - - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { - - // Clean the previously highlighted pixel: - overlay.clear(); - } - - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } else { - this.hideHighlightedPixel(overlay); - } - }; - - ns.BaseTool.prototype.hideHighlightedPixel = function(overlay) { - if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) { - try { - overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR); - } catch (e) { - window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed'); - } - this.highlightedPixelRow = null; - this.highlightedPixelCol = null; - } - }; - - ns.BaseTool.prototype.raiseSaveStateEvent = function (replayData) { - $.publish(Events.PISKEL_SAVE_STATE, { - type : pskl.service.HistoryService.REPLAY, - scope : this, - replay : replayData - }); - }; - - ns.BaseTool.prototype.getHelpText = function() { - return this.shortHelpText || this.helpText; - }; - - ns.BaseTool.prototype.getTooltipText = function(shortcut) { - var tpl = pskl.utils.Template.get('drawing-tool-tooltip-container-template'); - - var descriptors = ""; - if (Array.isArray(this.tooltipDescriptors)) { - this.tooltipDescriptors.forEach(function (descriptor) { - descriptors += this.getTooltipDescription(descriptor); - }.bind(this)); - } - - return pskl.utils.Template.replace(tpl, { - helptext : this.getHelpText(), - shortcut : shortcut, - descriptors : descriptors - }); - }; - - ns.BaseTool.prototype.getTooltipDescription = function(descriptor) { - var tpl; - if (descriptor.key) { - tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-template'); - descriptor.key = descriptor.key.toUpperCase(); - if (pskl.utils.UserAgent.isMac) { - descriptor.key = descriptor.key.replace('CTRL', 'CMD'); - } - } else { - tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-simple-template'); - } - return pskl.utils.Template.replace(tpl, descriptor); - }; - - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {}; - - /** - * Bresenham line algorithm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - x1 = pskl.utils.normalize(x1, 0); - y1 = pskl.utils.normalize(y1, 0); - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; - while(true){ - - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); - - if ((x0==x1) && (y0==y1)) { - break; - } - - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; -})(); -;(function () { - var ns = $.namespace('pskl.drawingtools'); - /** - * Abstract shape tool class, parent to all shape tools (rectangle, circle). - * Shape tools should override only the draw_ method - */ - ns.ShapeTool = function() { - // Shapes's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - - this.tooltipDescriptors = [ - {key : 'shift', description : 'Keep 1 to 1 ratio'} - ]; - }; - - pskl.utils.inherit(ns.ShapeTool, ns.BaseTool); - - /** - * @override - */ - ns.ShapeTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - $.publish(Events.DRAG_START, [col, row]); - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; - - ns.ShapeTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - var coords = this.getCoordinates_(col, row, event); - $.publish(Events.CURSOR_MOVED, [coords.col, coords.row]); - - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } - - // draw in overlay - this.draw_(coords.col, coords.row, color, overlay); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { - overlay.clear(); - var coords = this.getCoordinates_(col, row, event); - this.draw_(coords.col, coords.row, color, frame); - - $.publish(Events.DRAG_END, [col, row]); - this.raiseSaveStateEvent({ - col : col, - row : row, - startCol : this.startCol, - startRow : this.startRow, - color : color - }); - }; - - /** - * @override - */ - ns.ShapeTool.prototype.replay = function(frame, replayData) { - this.startCol = replayData.startCol; - this.startRow = replayData.startRow; - this.draw_(replayData.col, replayData.row, replayData.color, frame); - }; - - /** - * Transform the current coordinates based on the original event - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @param {Event} event current event (can be mousemove, mouseup ...) - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getCoordinates_ = function(col, row, event) { - if (event.shiftKey) { - return this.getScaledCoordinates_(col, row); - } else { - return {col : col, row : row}; - } - }; - - /** - * Transform the coordinates to preserve a square 1:1 ratio from the origin of the shape - * @param {Number} col current col/x coordinate in the frame - * @param {Number} row current row/y coordinate in the frame - * @return {Object} {row : Number, col : Number} - */ - ns.ShapeTool.prototype.getScaledCoordinates_ = function(col, row) { - var dX = this.startCol - col; - var absX = Math.abs(dX); - - var dY = this.startRow - row; - var absY = Math.abs(dY); - - var delta = Math.min(absX, absY); - row = this.startRow - ((dY/absY)*delta); - col = this.startCol - ((dX/absX)*delta); - - return { - col : col, - row : row - }; - }; - - ns.ShapeTool.prototype.draw_ = Constants.ABSTRACT_FUNCTION; - -})();;/** - * @provide pskl.drawingtools.SimplePen - * - * @require pskl.utils - */ -(function() { - var ns = $.namespace("pskl.drawingtools"); - - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; - - this.previousCol = null; - this.previousRow = null; - - this.pixels = []; - }; - - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - this.previousCol = col; - this.previousRow = row; - - overlay.setPixel(col, row, color); - - if (color === Constants.TRANSPARENT_COLOR) { - frame.setPixel(col, row, color); - } - this.pixels.push({ - col : col, - row : row, - color : color - }); - }; - - /** - * @override - */ - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay, event) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i=0===c})}function k(a){var b=Nb.split("|"),c=a.createDocumentFragment();if(c.createElement)for(;b.length;)c.createElement(b.pop());return c}function l(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function m(a,b){if(1===b.nodeType&&$.hasData(a)){var c,d,e,f=$._data(a),g=$._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)$.event.add(b,c,h[c][d])}g.data&&(g.data=$.extend({},g.data))}}function n(a,b){var c;1===b.nodeType&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),$.support.html5Clone&&a.innerHTML&&!$.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Xb.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.selected=a.defaultSelected:"input"===c||"textarea"===c?b.defaultValue=a.defaultValue:"script"===c&&b.text!==a.text&&(b.text=a.text),b.removeAttribute($.expando))}function o(a){return"undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName("*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll("*"):[]}function p(a){Xb.test(a.type)&&(a.defaultChecked=a.checked)}function q(a,b){if(b in a)return b;for(var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=qc.length;e--;)if(b=qc[e]+c,b in a)return b;return d}function r(a,b){return a=b||a,"none"===$.css(a,"display")||!$.contains(a.ownerDocument,a)}function s(a,b){for(var c,d,e=[],f=0,g=a.length;g>f;f++)c=a[f],c.style&&(e[f]=$._data(c,"olddisplay"),b?(e[f]||"none"!==c.style.display||(c.style.display=""),""===c.style.display&&r(c)&&(e[f]=$._data(c,"olddisplay",w(c.nodeName)))):(d=cc(c,"display"),e[f]||"none"===d||$._data(c,"olddisplay",d)));for(f=0;g>f;f++)c=a[f],c.style&&(b&&"none"!==c.style.display&&""!==c.style.display||(c.style.display=b?e[f]||"":"none"));return a}function t(a,b,c){var d=jc.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function u(a,b,c,d){for(var e=c===(d?"border":"content")?4:"width"===b?1:0,f=0;4>e;e+=2)"margin"===c&&(f+=$.css(a,c+pc[e],!0)),d?("content"===c&&(f-=parseFloat(cc(a,"padding"+pc[e]))||0),"margin"!==c&&(f-=parseFloat(cc(a,"border"+pc[e]+"Width"))||0)):(f+=parseFloat(cc(a,"padding"+pc[e]))||0,"padding"!==c&&(f+=parseFloat(cc(a,"border"+pc[e]+"Width"))||0));return f}function v(a,b,c){var d="width"===b?a.offsetWidth:a.offsetHeight,e=!0,f=$.support.boxSizing&&"border-box"===$.css(a,"boxSizing");if(0>=d){if(d=cc(a,b),(0>d||null==d)&&(d=a.style[b]),kc.test(d))return d;e=f&&($.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+u(a,b,c||(f?"border":"content"),e)+"px"}function w(a){if(mc[a])return mc[a];var b=$("<"+a+">").appendTo(P.body),c=b.css("display");return b.remove(),("none"===c||""===c)&&(dc=P.body.appendChild(dc||$.extend(P.createElement("iframe"),{frameBorder:0,width:0,height:0})),ec&&dc.createElement||(ec=(dc.contentWindow||dc.contentDocument).document,ec.write(""),ec.close()),b=ec.body.appendChild(ec.createElement(a)),c=cc(b,"display"),P.body.removeChild(dc)),mc[a]=c,c}function x(a,b,c,d){var e;if($.isArray(b))$.each(b,function(b,e){c||tc.test(a)?d(a,e):x(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==$.type(b))d(a,b);else for(e in b)x(a+"["+e+"]",b[e],c,d)}function y(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(bb),h=0,i=g.length;if($.isFunction(c))for(;i>h;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function z(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;for(var h,i=a[f],j=0,k=i?i.length:0,l=a===Jc;k>j&&(l||!h);j++)h=i[j](c,d,e),"string"==typeof h&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=z(a,c,d,e,h,g)));return!l&&h||g["*"]||(h=z(a,c,d,e,"*",g)),h}function A(a,c){var d,e,f=$.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&$.extend(!0,a,e)}function B(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);for(;"*"===j[0];)j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}return g?(g!==j[0]&&j.unshift(g),d[g]):void 0}function C(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;if(a.dataFilter&&(b=a.dataFilter(b,a.dataType)),g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if("*"!==e){if("*"!==h&&h!==e){if(c=i[h+" "+e]||i["* "+e],!c)for(d in i)if(f=d.split(" "),f[1]===e&&(c=i[h+" "+f[0]]||i["* "+f[0]])){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function D(){try{return new a.XMLHttpRequest}catch(b){}}function E(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function F(){return setTimeout(function(){Uc=b},0),Uc=$.now()}function G(a,b){$.each(b,function(b,c){for(var d=($c[b]||[]).concat($c["*"]),e=0,f=d.length;f>e;e++)if(d[e].call(a,b,c))return})}function H(a,b,c){var d,e=0,f=Zc.length,g=$.Deferred().always(function(){delete h.elem}),h=function(){for(var b=Uc||F(),c=Math.max(0,i.startTime+i.duration-b),d=1-(c/i.duration||0),e=0,f=i.tweens.length;f>e;e++)i.tweens[e].run(d);return g.notifyWith(a,[i,d,c]),1>d&&f?c:(g.resolveWith(a,[i]),!1)},i=g.promise({elem:a,props:$.extend({},b),opts:$.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Uc||F(),duration:c.duration,tweens:[],createTween:function(b,c){var d=$.Tween(a,i.opts,b,c,i.opts.specialEasing[b]||i.opts.easing);return i.tweens.push(d),d},stop:function(b){for(var c=0,d=b?i.tweens.length:0;d>c;c++)i.tweens[c].run(1);return b?g.resolveWith(a,[i,b]):g.rejectWith(a,[i,b]),this}}),j=i.props;for(I(j,i.opts.specialEasing);f>e;e++)if(d=Zc[e].call(i,a,j,i.opts))return d;return G(i,j),$.isFunction(i.opts.start)&&i.opts.start.call(a,i),$.fx.timer($.extend(h,{anim:i,queue:i.opts.queue,elem:a})),i.progress(i.opts.progress).done(i.opts.done,i.opts.complete).fail(i.opts.fail).always(i.opts.always)}function I(a,b){var c,d,e,f,g;for(c in a)if(d=$.camelCase(c),e=b[d],f=a[c],$.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=$.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function J(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],p=a.nodeType&&r(a);c.queue||(j=$._queueHooks(a,"fx"),null==j.unqueued&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,$.queue(a,"fx").length||j.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],"inline"===$.css(a,"display")&&"none"===$.css(a,"float")&&($.support.inlineBlockNeedsLayout&&"inline"!==w(a.nodeName)?m.zoom=1:m.display="inline-block")),c.overflow&&(m.overflow="hidden",$.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(f=b[d],Wc.exec(f)){if(delete b[d],f===(p?"hide":"show"))continue;o.push(d)}if(g=o.length)for(h=$._data(a,"fxshow")||$._data(a,"fxshow",{}),p?$(a).show():l.done(function(){$(a).hide()}),l.done(function(){var b;$.removeData(a,"fxshow",!0);for(b in n)$.style(a,b,n[b])}),d=0;g>d;d++)e=o[d],i=l.createTween(e,p?h[e]:0),n[e]=h[e]||$.style(a,e),e in h||(h[e]=i.start,p&&(i.end=i.start,i.start="width"===e||"height"===e?1:0))}function K(a,b,c,d,e){return new K.prototype.init(a,b,c,d,e)}function L(a,b){for(var c,d={height:a},e=0;4>e;e+=2-b)c=pc[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function M(a){return $.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}var N,O,P=a.document,Q=a.location,R=a.navigator,S=a.jQuery,T=a.$,U=Array.prototype.push,V=Array.prototype.slice,W=Array.prototype.indexOf,X=Object.prototype.toString,Y=Object.prototype.hasOwnProperty,Z=String.prototype.trim,$=function(a,b){return new $.fn.init(a,b,N)},_=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,ab=/\S/,bb=/\s+/,cb=ab.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,db=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,eb=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,fb=/^[\],:{}\s]*$/,gb=/(?:^|:|,)(?:\s*\[)+/g,hb=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,ib=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,jb=/^-ms-/,kb=/-([\da-z])/gi,lb=function(a,b){return(b+"").toUpperCase()},mb=function(){P.addEventListener?(P.removeEventListener("DOMContentLoaded",mb,!1),$.ready()):"complete"===P.readyState&&(P.detachEvent("onreadystatechange",mb),$.ready())},nb={};$.fn=$.prototype={constructor:$,init:function(a,c,d){var e,f,g;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if("string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:db.exec(a),!e||!e[1]&&c)return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a);if(e[1])return c=c instanceof $?c[0]:c,g=c&&c.nodeType?c.ownerDocument||c:P,a=$.parseHTML(e[1],g,!0),eb.test(e[1])&&$.isPlainObject(c)&&this.attr.call(a,c,!0),$.merge(this,a);if(f=P.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return d.find(a);this.length=1,this[0]=f}return this.context=P,this.selector=a,this}return $.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),$.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return V.call(this)},get:function(a){return null==a?this.toArray():0>a?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=$.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,"find"===b?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return $.each(this,a,b)},ready:function(a){return $.ready.promise().done(a),this},eq:function(a){return a=+a,-1===a?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(V.apply(this,arguments),"slice",V.call(arguments).join(","))},map:function(a){return this.pushStack($.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:U,sort:[].sort,splice:[].splice},$.fn.init.prototype=$.fn,$.extend=$.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;for("boolean"==typeof h&&(k=h,h=arguments[1]||{},i=2),"object"==typeof h||$.isFunction(h)||(h={}),j===i&&(h=this,--i);j>i;i++)if(null!=(a=arguments[i]))for(c in a)d=h[c],e=a[c],h!==e&&(k&&e&&($.isPlainObject(e)||(f=$.isArray(e)))?(f?(f=!1,g=d&&$.isArray(d)?d:[]):g=d&&$.isPlainObject(d)?d:{},h[c]=$.extend(k,g,e)):e!==b&&(h[c]=e));return h},$.extend({noConflict:function(b){return a.$===$&&(a.$=T),b&&a.jQuery===$&&(a.jQuery=S),$},isReady:!1,readyWait:1,holdReady:function(a){a?$.readyWait++:$.ready(!0)},ready:function(a){if(a===!0?!--$.readyWait:!$.isReady){if(!P.body)return setTimeout($.ready,1);$.isReady=!0,a!==!0&&--$.readyWait>0||(O.resolveWith(P,[$]),$.fn.trigger&&$(P).trigger("ready").off("ready"))}},isFunction:function(a){return"function"===$.type(a)},isArray:Array.isArray||function(a){return"array"===$.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return null==a?String(a):nb[X.call(a)]||"object"},isPlainObject:function(a){if(!a||"object"!==$.type(a)||a.nodeType||$.isWindow(a))return!1;try{if(a.constructor&&!Y.call(a,"constructor")&&!Y.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||Y.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return a&&"string"==typeof a?("boolean"==typeof b&&(c=b,b=0),b=b||P,(d=eb.exec(a))?[b.createElement(d[1])]:(d=$.buildFragment([a],b,c?null:[]),$.merge([],(d.cacheable?$.clone(d.fragment):d.fragment).childNodes))):null},parseJSON:function(b){return b&&"string"==typeof b?(b=$.trim(b),a.JSON&&a.JSON.parse?a.JSON.parse(b):fb.test(b.replace(hb,"@").replace(ib,"]").replace(gb,""))?new Function("return "+b)():void $.error("Invalid JSON: "+b)):null},parseXML:function(c){var d,e;if(!c||"string"!=typeof c)return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return d&&d.documentElement&&!d.getElementsByTagName("parsererror").length||$.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&ab.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(jb,"ms-").replace(kb,lb)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||$.isFunction(a);if(d)if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;g>f&&c.apply(a[f++],d)!==!1;);else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;g>f&&c.call(a[f],f,a[f++])!==!1;);return a},trim:Z?function(a){return null==a?"":Z.call(a)}:function(a){return null==a?"":a.toString().replace(cb,"")},makeArray:function(a,b){var c,d=b||[];return null!=a&&(c=$.type(a),null==a.length||"string"===c||"function"===c||"regexp"===c||$.isWindow(a)?U.call(d,a):$.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(W)return W.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if("number"==typeof d)for(;d>f;f++)a[e++]=c[f];else for(;c[f]!==b;)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;for(c=!!c;g>f;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof $||i!==b&&"number"==typeof i&&(i>0&&a[0]&&a[i-1]||0===i||$.isArray(a));if(j)for(;i>h;h++)e=c(a[h],h,d),null!=e&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),null!=e&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return"string"==typeof c&&(d=a[c],c=a,a=d),$.isFunction(a)?(e=V.call(arguments,2),f=function(){return a.apply(c,e.concat(V.call(arguments)))},f.guid=a.guid=a.guid||f.guid||$.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=null==d,k=0,l=a.length;if(d&&"object"==typeof d){for(k in d)$.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){if(i=h===b&&$.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call($(a),c)}):(c.call(a,e),c=null)),c)for(;l>k;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),$.ready.promise=function(b){if(!O)if(O=$.Deferred(),"complete"===P.readyState||"loading"!==P.readyState&&P.addEventListener)setTimeout($.ready,1);else if(P.addEventListener)P.addEventListener("DOMContentLoaded",mb,!1),a.addEventListener("load",$.ready,!1);else{P.attachEvent("onreadystatechange",mb),a.attachEvent("onload",$.ready);var c=!1;try{c=null==a.frameElement&&P.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!$.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}$.ready()}}()}return O.promise(b)},$.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){nb["[object "+b+"]"]=b.toLowerCase()}),N=$(P);var ob={};$.Callbacks=function(a){a="string"==typeof a?ob[a]||c(a):$.extend({},a);var d,e,f,g,h,i,j=[],k=!a.once&&[],l=function(b){for(d=a.memory&&b,e=!0,i=g||0,g=0,h=j.length,f=!0;j&&h>i;i++)if(j[i].apply(b[0],b[1])===!1&&a.stopOnFalse){d=!1;break}f=!1,j&&(k?k.length&&l(k.shift()):d?j=[]:m.disable())},m={add:function(){if(j){var b=j.length;!function c(b){$.each(b,function(b,d){!$.isFunction(d)||a.unique&&m.has(d)?d&&d.length&&c(d):j.push(d)})}(arguments),f?h=j.length:d&&(g=b,l(d))}return this},remove:function(){return j&&$.each(arguments,function(a,b){for(var c;(c=$.inArray(b,j,c))>-1;)j.splice(c,1),f&&(h>=c&&h--,i>=c&&i--)}),this},has:function(a){return $.inArray(a,j)>-1},empty:function(){return j=[],this},disable:function(){return j=k=d=b,this},disabled:function(){return!j},lock:function(){return k=b,d||m.disable(),this},locked:function(){return!k},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],!j||e&&!k||(f?k.push(b):l(b)),this},fire:function(){return m.fireWith(this,arguments),this},fired:function(){return!!e}};return m},$.extend({Deferred:function(a){var b=[["resolve","done",$.Callbacks("once memory"),"resolved"],["reject","fail",$.Callbacks("once memory"),"rejected"],["notify","progress",$.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return $.Deferred(function(c){$.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]]($.isFunction(g)?function(){var a=g.apply(this,arguments);a&&$.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return"object"==typeof a?$.extend(a,d):d}},e={};return d.pipe=d.then,$.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b,c,d,e=0,f=V.call(arguments),g=f.length,h=1!==g||a&&$.isFunction(a.promise)?g:0,i=1===h?a:$.Deferred(),j=function(a,c,d){return function(e){c[a]=this,d[a]=arguments.length>1?V.call(arguments):e,d===b?i.notifyWith(c,d):--h||i.resolveWith(c,d)}};if(g>1)for(b=new Array(g),c=new Array(g),d=new Array(g);g>e;e++)f[e]&&$.isFunction(f[e].promise)?f[e].promise().done(j(e,d,f)).fail(i.reject).progress(j(e,c,b)):--h;return h||i.resolveWith(d,f),i.promise()}}),$.support=function(){var b,c,d,e,f,g,h,i,j,k,l,m=P.createElement("div");if(m.setAttribute("className","t"),m.innerHTML="
         
        a",c=m.getElementsByTagName("*"),d=m.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5",!c||!c.length||!d)return{};e=P.createElement("select"),f=e.appendChild(P.createElement("option")),g=m.getElementsByTagName("input")[0],b={leadingWhitespace:3===m.firstChild.nodeType,tbody:!m.getElementsByTagName("tbody").length,htmlSerialize:!!m.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:"/a"===d.getAttribute("href"),opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:"on"===g.value,optSelected:f.selected,getSetAttribute:"t"!==m.className,enctype:!!P.createElement("form").enctype,html5Clone:"<:nav>"!==P.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===P.compatMode,submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},g.checked=!0,b.noCloneChecked=g.cloneNode(!0).checked,e.disabled=!0,b.optDisabled=!f.disabled;try{delete m.test}catch(n){b.deleteExpando=!1}if(!m.addEventListener&&m.attachEvent&&m.fireEvent&&(m.attachEvent("onclick",l=function(){b.noCloneEvent=!1}),m.cloneNode(!0).fireEvent("onclick"),m.detachEvent("onclick",l)),g=P.createElement("input"),g.value="t",g.setAttribute("type","radio"),b.radioValue="t"===g.value,g.setAttribute("checked","checked"),g.setAttribute("name","t"),m.appendChild(g),h=P.createDocumentFragment(),h.appendChild(m.lastChild),b.checkClone=h.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=g.checked,h.removeChild(g),h.appendChild(m),m.attachEvent)for(j in{submit:!0,change:!0,focusin:!0})i="on"+j,k=i in m,k||(m.setAttribute(i,"return;"),k="function"==typeof m[i]),b[j+"Bubbles"]=k;return $(function(){var c,d,e,f,g="padding:0;margin:0;border:0;display:block;overflow:hidden;",h=P.getElementsByTagName("body")[0];h&&(c=P.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",h.insertBefore(c,h.firstChild),d=P.createElement("div"),c.appendChild(d),d.innerHTML="
        t
        ",e=d.getElementsByTagName("td"),e[0].style.cssText="padding:0;margin:0;border:0;display:none",k=0===e[0].offsetHeight,e[0].style.display="",e[1].style.display="none",b.reliableHiddenOffsets=k&&0===e[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=4===d.offsetWidth,b.doesNotIncludeMarginInBodyOffset=1!==h.offsetTop,a.getComputedStyle&&(b.pixelPosition="1%"!==(a.getComputedStyle(d,null)||{}).top,b.boxSizingReliable="4px"===(a.getComputedStyle(d,null)||{width:"4px"}).width,f=P.createElement("div"),f.style.cssText=d.style.cssText=g,f.style.marginRight=f.style.width="0",d.style.width="1px",d.appendChild(f),b.reliableMarginRight=!parseFloat((a.getComputedStyle(f,null)||{}).marginRight)),"undefined"!=typeof d.style.zoom&&(d.innerHTML="",d.style.cssText=g+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.style.overflow="visible",d.innerHTML="
        ",d.firstChild.style.width="5px",b.shrinkWrapBlocks=3!==d.offsetWidth,c.style.zoom=1),h.removeChild(c),c=d=e=f=null)}),h.removeChild(m),c=d=e=f=g=h=m=null,b}();var pb=/^(?:\{.*\}|\[.*\])$/,qb=/([A-Z])/g;$.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+($.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?$.cache[a[$.expando]]:a[$.expando],!!a&&!e(a)},data:function(a,c,d,e){if($.acceptData(a)){var f,g,h=$.expando,i="string"==typeof c,j=a.nodeType,k=j?$.cache:a,l=j?a[h]:a[h]&&h;if(l&&k[l]&&(e||k[l].data)||!i||d!==b)return l||(j?a[h]=l=$.deletedIds.pop()||++$.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=$.noop)),("object"==typeof c||"function"==typeof c)&&(e?k[l]=$.extend(k[l],c):k[l].data=$.extend(k[l].data,c)),f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[$.camelCase(c)]=d),i?(g=f[c],null==g&&(g=f[$.camelCase(c)])):g=f,g}},removeData:function(a,b,c){if($.acceptData(a)){var d,f,g,h=a.nodeType,i=h?$.cache:a,j=h?a[$.expando]:$.expando;if(i[j]){if(b&&(d=c?i[j]:i[j].data)){$.isArray(b)||(b in d?b=[b]:(b=$.camelCase(b),b=b in d?[b]:b.split(" ")));for(f=0,g=b.length;g>f;f++)delete d[b[f]];if(!(c?e:$.isEmptyObject)(d))return}(c||(delete i[j].data,e(i[j])))&&(h?$.cleanData([a],!0):$.support.deleteExpando||i!=i.window?delete i[j]:i[j]=null)}}},_data:function(a,b,c){return $.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&$.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),$.fn.extend({data:function(a,c){var e,f,g,h,i,j=this[0],k=0,l=null;if(a===b){if(this.length&&(l=$.data(j),1===j.nodeType&&!$._data(j,"parsedAttrs"))){for(g=j.attributes,i=g.length;i>k;k++)h=g[k].name,0===h.indexOf("data-")&&(h=$.camelCase(h.substring(5)),d(j,h,l[h]));$._data(j,"parsedAttrs",!0)}return l}return"object"==typeof a?this.each(function(){$.data(this,a)}):(e=a.split(".",2),e[1]=e[1]?"."+e[1]:"",f=e[1]+"!",$.access(this,function(c){return c===b?(l=this.triggerHandler("getData"+f,[e[0]]),l===b&&j&&(l=$.data(j,a),l=d(j,a,l)),l===b&&e[1]?this.data(e[0]):l):(e[1]=c,void this.each(function(){var b=$(this);b.triggerHandler("setData"+f,e),$.data(this,a,c),b.triggerHandler("changeData"+f,e)}))},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){$.removeData(this,a)})}}),$.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=$._data(a,b),c&&(!d||$.isArray(c)?d=$._data(a,b,$.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=$.queue(a,b),d=c.shift(),e=$._queueHooks(a,b),f=function(){$.dequeue(a,b)};"inprogress"===d&&(d=c.shift()),d&&("fx"===b&&c.unshift("inprogress"),delete e.stop,d.call(a,f,e)),!c.length&&e&&e.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return $._data(a,c)||$._data(a,c,{empty:$.Callbacks("once memory").add(function(){$.removeData(a,b+"queue",!0),$.removeData(a,c,!0)})})}}),$.fn.extend({queue:function(a,c){var d=2;return"string"!=typeof a&&(c=a,a="fx",d--),arguments.length1)},removeAttr:function(a){return this.each(function(){$.removeAttr(this,a)})},prop:function(a,b){return $.access(this,$.prop,a,b,arguments.length>1)},removeProp:function(a){return a=$.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if($.isFunction(a))return this.each(function(b){$(this).addClass(a.call(this,b,this.className))});if(a&&"string"==typeof a)for(b=a.split(bb),c=0,d=this.length;d>c;c++)if(e=this[c],1===e.nodeType)if(e.className||1!==b.length){for(f=" "+e.className+" ",g=0,h=b.length;h>g;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=$.trim(f)}else e.className=a;return this},removeClass:function(a){var c,d,e,f,g,h,i;if($.isFunction(a))return this.each(function(b){$(this).removeClass(a.call(this,b,this.className))});if(a&&"string"==typeof a||a===b)for(c=(a||"").split(bb),h=0,i=this.length;i>h;h++)if(e=this[h],1===e.nodeType&&e.className){for(d=(" "+e.className+" ").replace(ub," "),f=0,g=c.length;g>f;f++)for(;d.indexOf(" "+c[f]+" ")>-1;)d=d.replace(" "+c[f]+" "," ");e.className=a?$.trim(d):""}return this},toggleClass:function(a,b){var c=typeof a,d="boolean"==typeof b;return this.each($.isFunction(a)?function(c){$(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c)for(var e,f=0,g=$(this),h=b,i=a.split(bb);e=i[f++];)h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e);else("undefined"===c||"boolean"===c)&&(this.className&&$._data(this,"__className__",this.className),this.className=this.className||a===!1?"":$._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ub," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];{if(arguments.length)return e=$.isFunction(a),this.each(function(d){var f,g=$(this);1===this.nodeType&&(f=e?a.call(this,d,g.val()):a,null==f?f="":"number"==typeof f?f+="":$.isArray(f)&&(f=$.map(f,function(a){return null==a?"":a+""})),c=$.valHooks[this.type]||$.valHooks[this.nodeName.toLowerCase()],c&&"set"in c&&c.set(this,f,"value")!==b||(this.value=f))});if(f)return c=$.valHooks[f.type]||$.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,"string"==typeof d?d.replace(vb,""):null==d?"":d)}}}),$.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i="select-one"===a.type;if(0>f)return null;for(c=i?f:0,d=i?f+1:h.length;d>c;c++)if(e=h[c],!(!e.selected||($.support.optDisabled?e.disabled:null!==e.getAttribute("disabled"))||e.parentNode.disabled&&$.nodeName(e.parentNode,"optgroup"))){if(b=$(e).val(),i)return b;g.push(b)}return i&&!g.length&&h.length?$(h[f]).val():g},set:function(a,b){var c=$.makeArray(b);return $(a).find("option").each(function(){this.selected=$.inArray($(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(a&&3!==i&&8!==i&&2!==i)return e&&$.isFunction($.fn[c])?$(a)[c](d):"undefined"==typeof a.getAttribute?$.prop(a,c,d):(h=1!==i||!$.isXMLDoc(a),h&&(c=c.toLowerCase(),g=$.attrHooks[c]||(zb.test(c)?sb:rb)),d!==b?null===d?void $.removeAttr(a,c):g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d):g&&"get"in g&&h&&null!==(f=g.get(a,c))?f:(f=a.getAttribute(c),null===f?b:f))},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&1===a.nodeType)for(d=b.split(bb);g=0:void 0}})});var Bb=/^(?:textarea|input|select)$/i,Cb=/^([^\.]*|)(?:\.(.+)|)$/,Db=/(?:^|\s)hover(\.\S+|)\b/,Eb=/^key/,Fb=/^(?:mouse|contextmenu)|click/,Gb=/^(?:focusinfocus|focusoutblur)$/,Hb=function(a){return $.event.special.hover?a:a.replace(Db,"mouseenter$1 mouseleave$1")};$.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q;if(3!==a.nodeType&&8!==a.nodeType&&c&&d&&(g=$._data(a))){for(d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=$.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return"undefined"==typeof $||a&&$.event.triggered===a.type?b:$.event.dispatch.apply(h.elem,arguments)},h.elem=a),c=$.trim(Hb(c)).split(" "),j=0;j=0&&(q=q.slice(0,-1),h=!0),q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),e&&!$.event.customEvent[q]||$.event.global[q]))if(c="object"==typeof c?c[$.expando]?c:new $.Event(q,c):new $.Event(q),c.type=q,c.isTrigger=!0,c.exclusive=h,c.namespace=r.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,l=q.indexOf(":")<0?"on"+q:"",e){if(c.result=b,c.target||(c.target=e),d=null!=d?$.makeArray(d):[],d.unshift(c),m=$.event.special[q]||{},!m.trigger||m.trigger.apply(e,d)!==!1){if(o=[[e,m.bindType||q]],!f&&!m.noBubble&&!$.isWindow(e)){for(p=m.delegateType||q,j=Gb.test(p+q)?e:e.parentNode,k=e;j;j=j.parentNode)o.push([j,p]),k=j;k===(e.ownerDocument||P)&&o.push([k.defaultView||k.parentWindow||a,p])}for(i=0;id;d++)l=n[d],m=l.selector,i[m]===b&&(i[m]=g.is(m)),i[m]&&k.push(l);k.length&&s.push({elem:f,matches:k})}for(n.length>o&&s.push({elem:this,matches:n.slice(o)}),d=0;d0?this.on(b,null,a,c):this.trigger(b)},Eb.test(b)&&($.event.fixHooks[b]=$.event.keyHooks),Fb.test(b)&&($.event.fixHooks[b]=$.event.mouseHooks)}),function(a,b){function c(a,b,c,d){for(var e=0,f=b.length;f>e;e++)fb(a,b[e],c,d)}function d(a,b,d,e,f,g){var h,i=gb.setFilters[b.toLowerCase()];return i||fb.error(b),(a||!(h=f))&&c(a||"*",e,h=[],f),h.length>0?i(h,d,g):[]}function e(a,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=0,r=h.length,s=S.POS,t=new RegExp("^"+s.source+"(?!"+y+")","i"),u=function(){for(var a=1,c=arguments.length-2;c>a;a++)arguments[a]===b&&(i[a]=b)};r>q;q++){for(s.exec(""),a=h[q],l=[],k=0,m=g;i=s.exec(a);)p=s.lastIndex=i.index+i[0].length,p>k&&(o=a.slice(k,i.index),k=p,n=[e],I.test(o)&&(m&&(n=m),m=g),(j=O.test(o))&&(o=o.slice(0,-5).replace(I,"$&*")),i.length>1&&i[0].replace(t,u),m=d(o,i[1],i[2],n,m,j));m?(l=l.concat(m),(o=a.slice(k))&&")"!==o?I.test(o)?c(o,l,f,g):fb(o,e,f,g?g.concat(m):m):w.apply(f,l)):fb(a,e,f,g)}return 1===r?f:fb.uniqueSort(f)}function f(a,b,c){for(var d,e,f,g=[],h=0,i=K.exec(a),j=!i.pop()&&!i.pop(),k=j&&a.match(J)||[""],l=gb.preFilter,m=gb.filter,n=!c&&b!==p;null!=(e=k[h])&&j;h++)for(g.push(d=[]),n&&(e=" "+e);e;){j=!1,(i=I.exec(e))&&(e=e.slice(i[0].length),j=d.push({part:i.pop().replace(H," "),captures:i}));for(f in m)!(i=S[f].exec(e))||l[f]&&!(i=l[f](i,b,c))||(e=e.slice(i.shift().length),j=d.push({part:f,captures:i}));if(!j)break}return j||fb.error(a),g}function g(a,b,c){var d=b.dir,e=u++;return a||(a=function(a){return a===c}),b.first?function(b,c){for(;b=b[d];)if(1===b.nodeType)return a(b,c)&&b}:function(b,c){for(var f,g=e+"."+l,h=g+"."+k;b=b[d];)if(1===b.nodeType){if((f=b[x])===h)return b.sizset;if("string"==typeof f&&0===f.indexOf(g)){if(b.sizset)return b}else{if(b[x]=h,a(b,c))return b.sizset=!0,b;b.sizset=!1}}}}function h(a,b){return a?function(c,d){var e=b(c,d);return e&&a(e===!0?c:e,d)}:b}function i(a,b,c){for(var d,e,f=0;d=a[f];f++)gb.relative[d.part]?e=g(e,gb.relative[d.part],b):(d.captures.push(b,c),e=h(e,gb.filter[d.part].apply(null,d.captures)));return e}function j(a){return function(b,c){for(var d,e=0;d=a[e];e++)if(d(b,c))return!0;return!1}}var k,l,m,n,o,p=a.document,q=p.documentElement,r="undefined",s=!1,t=!0,u=0,v=[].slice,w=[].push,x=("sizcache"+Math.random()).replace(".",""),y="[\\x20\\t\\r\\n\\f]",z="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",A=z.replace("w","w#"),B="([*^$|!~]?=)",C="\\["+y+"*("+z+")"+y+"*(?:"+B+y+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+A+")|)|)"+y+"*\\]",D=":("+z+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",E=":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",F=y+"*([\\x20\\t\\r\\n\\f>+~])"+y+"*",G="(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|"+C+"|"+D.replace(2,7)+"|[^\\\\(),])+",H=new RegExp("^"+y+"+|((?:^|[^\\\\])(?:\\\\.)*)"+y+"+$","g"),I=new RegExp("^"+F),J=new RegExp(G+"?(?="+y+"*,|$)","g"),K=new RegExp("^(?:(?!,)(?:(?:^|,)"+y+"*"+G+")*?|"+y+"*(.*?))(\\)|$)"),L=new RegExp(G.slice(19,-6)+"\\x20\\t\\r\\n\\f>+~])+|"+F,"g"),M=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,N=/[\x20\t\r\n\f]*[+~]/,O=/:not\($/,P=/h\d/i,Q=/input|select|textarea|button/i,R=/\\(?!\\)/g,S={ID:new RegExp("^#("+z+")"),CLASS:new RegExp("^\\.("+z+")"),NAME:new RegExp("^\\[name=['\"]?("+z+")['\"]?\\]"),TAG:new RegExp("^("+z.replace("[-","[-\\*")+")"),ATTR:new RegExp("^"+C),PSEUDO:new RegExp("^"+D),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+y+"*(even|odd|(([+-]|)(\\d*)n|)"+y+"*(?:([+-]|)"+y+"*(\\d+)|))"+y+"*\\)|)","i"),POS:new RegExp(E,"ig"),needsContext:new RegExp("^"+y+"*[>+~]|"+E,"i")},T={},U=[],V={},W=[],X=function(a){return a.sizzleFilter=!0,a},Y=function(a){return function(b){return"input"===b.nodeName.toLowerCase()&&b.type===a}},Z=function(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}},_=function(a){var b=!1,c=p.createElement("div");try{b=a(c)}catch(d){}return c=null,b},ab=_(function(a){a.innerHTML="";var b=typeof a.lastChild.getAttribute("multiple");return"boolean"!==b&&"string"!==b}),bb=_(function(a){a.id=x+0,a.innerHTML="
        ",q.insertBefore(a,q.firstChild);var b=p.getElementsByName&&p.getElementsByName(x).length===2+p.getElementsByName(x+0).length;return o=!p.getElementById(x),q.removeChild(a),b}),cb=_(function(a){return a.appendChild(p.createComment("")),0===a.getElementsByTagName("*").length}),db=_(function(a){return a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!==r&&"#"===a.firstChild.getAttribute("href")}),eb=_(function(a){return a.innerHTML="",a.getElementsByClassName&&0!==a.getElementsByClassName("e").length?(a.lastChild.className="e",1!==a.getElementsByClassName("e").length):!1}),fb=function(a,b,c,d){c=c||[],b=b||p;var e,f,g,h,i=b.nodeType;if(1!==i&&9!==i)return[];if(!a||"string"!=typeof a)return c;if(g=ib(b),!g&&!d&&(e=M.exec(a)))if(h=e[1]){if(9===i){if(f=b.getElementById(h),!f||!f.parentNode)return c;if(f.id===h)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(h))&&jb(b,f)&&f.id===h)return c.push(f),c}else{if(e[2])return w.apply(c,v.call(b.getElementsByTagName(a),0)),c;if((h=e[3])&&eb&&b.getElementsByClassName)return w.apply(c,v.call(b.getElementsByClassName(h),0)),c}return mb(a,b,c,d,g)},gb=fb.selectors={cacheLength:50,match:S,order:["ID","TAG"],attrHandle:{},createPseudo:X,find:{ID:o?function(a,b,c){if(typeof b.getElementById!==r&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==r&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==r&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:cb?function(a,b){return typeof b.getElementsByTagName!==r?b.getElementsByTagName(a):void 0}:function(a,b){var c=b.getElementsByTagName(a);if("*"===a){for(var d,e=[],f=0;d=c[f];f++)1===d.nodeType&&e.push(d);return e}return c}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(R,""),a[3]=(a[4]||a[5]||"").replace(R,""),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1]?(a[2]||fb.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*("even"===a[2]||"odd"===a[2])),a[4]=+(a[6]+a[7]||"odd"===a[2])):a[2]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=a[4];return S.CHILD.test(a[0])?null:(c&&(b=K.exec(c))&&b.pop()&&(a[0]=a[0].slice(0,b[0].length-c.length-1),c=b[0].slice(0,-1)),a.splice(2,3,c||a[3]),a)}},filter:{ID:o?function(a){return a=a.replace(R,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(R,""),function(b){var c=typeof b.getAttributeNode!==r&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return"*"===a?function(){return!0}:(a=a.replace(R,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=T[a];return b||(b=T[a]=new RegExp("(^|"+y+")"+a+"("+y+"|$)"),U.push(a),U.length>gb.cacheLength&&delete T[U.shift()]),function(a){return b.test(a.className||typeof a.getAttribute!==r&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=fb.attr(d,a),f=e+"";if(null==e)return"!="===b;switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&0===f.indexOf(c);case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return null!=fb.attr(b,a)}},CHILD:function(a,b,c,d){if("nth"===a){var e=u++;return function(a){var b,f,g=0,h=a;if(1===c&&0===d)return!0;if(b=a.parentNode,b&&(b[x]!==e||!a.sizset)){for(h=b.firstChild;h&&(1!==h.nodeType||(h.sizset=++g,h!==a));h=h.nextSibling);b[x]=e}return f=a.sizset-d,0===c?0===f:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":for(;c=c.previousSibling;)if(1===c.nodeType)return!1;if("first"===a)return!0;c=b;case"last":for(;c=c.nextSibling;)if(1===c.nodeType)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e=gb.pseudos[a]||gb.pseudos[a.toLowerCase()];return e||fb.error("unsupported pseudo: "+a),e.sizzleFilter?e(b,c,d):e}},pseudos:{not:X(function(a,b,c){var d=lb(a.replace(H,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!gb.pseudos.empty(a)},empty:function(a){var b;for(a=a.firstChild;a;){if(a.nodeName>"@"||3===(b=a.nodeType)||4===b)return!1;a=a.nextSibling}return!0},contains:X(function(a){return function(b){return(b.textContent||b.innerText||kb(b)).indexOf(a)>-1}}),has:X(function(a){return function(b){return fb(a,b).length>0}}),header:function(a){return P.test(a.nodeName)},text:function(a){var b,c;return"input"===a.nodeName.toLowerCase()&&"text"===(b=a.type)&&(null==(c=a.getAttribute("type"))||c.toLowerCase()===b)},radio:Y("radio"),checkbox:Y("checkbox"),file:Y("file"),password:Y("password"),image:Y("image"),submit:Z("submit"),reset:Z("reset"),button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},input:function(a){return Q.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return!(a!==b.activeElement||b.hasFocus&&!b.hasFocus()||!a.type&&!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(a,b,c){for(var d=[],e=c?1:0,f=a.length;f>e;e+=2)d.push(a[e]);return d},odd:function(a,b,c){for(var d=[],e=c?0:1,f=a.length;f>e;e+=2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}};gb.setFilters.nth=gb.setFilters.eq,gb.filters=gb.pseudos,db||(gb.attrHandle={href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}}),bb&&(gb.order.push("NAME"),gb.find.NAME=function(a,b){return typeof b.getElementsByName!==r?b.getElementsByName(a):void 0}),eb&&(gb.order.splice(1,0,"CLASS"),gb.find.CLASS=function(a,b,c){return typeof b.getElementsByClassName===r||c?void 0:b.getElementsByClassName(a)});try{v.call(q.childNodes,0)[0].nodeType}catch(hb){v=function(a){for(var b,c=[];b=this[a];a++)c.push(b);return c}}var ib=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},jb=fb.contains=q.compareDocumentPosition?function(a,b){return!!(16&a.compareDocumentPosition(b))}:q.contains?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b.parentNode;return a===d||!!(d&&1===d.nodeType&&c.contains&&c.contains(d))}:function(a,b){for(;b=b.parentNode;)if(b===a)return!0;return!1},kb=fb.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(1===e||9===e||11===e){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=kb(a)}else if(3===e||4===e)return a.nodeValue}else for(;b=a[d];d++)c+=kb(b);return c};fb.attr=function(a,b){var c,d=ib(a);return d||(b=b.toLowerCase()),gb.attrHandle[b]?gb.attrHandle[b](a):ab||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?"boolean"==typeof a[b]?a[b]?b:null:c.specified?c.value:null:null)},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},[0,0].sort(function(){return t=0}),q.compareDocumentPosition?m=function(a,b){return a===b?(s=!0,0):(a.compareDocumentPosition&&b.compareDocumentPosition?4&a.compareDocumentPosition(b):a.compareDocumentPosition)?-1:1}:(m=function(a,b){if(a===b)return s=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return n(a,b);if(!g)return-1;if(!h)return 1;for(;i;)e.unshift(i),i=i.parentNode;for(i=h;i;)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;c>j&&d>j;j++)if(e[j]!==f[j])return n(e[j],f[j]);return j===c?n(a,f[j],-1):n(e[j],b,1)},n=function(a,b,c){if(a===b)return c;for(var d=a.nextSibling;d;){if(d===b)return-1;d=d.nextSibling}return 1}),fb.uniqueSort=function(a){var b,c=1;if(m&&(s=t,a.sort(m),s))for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a};var lb=fb.compile=function(a,b,c){var d,e,g,h=V[a];if(h&&h.context===b)return h;for(e=f(a,b,c),g=0;d=e[g];g++)e[g]=i(d,b,c);return h=V[a]=j(e),h.context=b,h.runs=h.dirruns=0,W.push(a),W.length>gb.cacheLength&&delete V[W.shift()],h};fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){return fb(b,null,null,[a]).length>0};var mb=function(a,b,c,d,f){a=a.replace(H,"$1");var g,h,i,j,m,n,o,p,q,r=a.match(J),s=a.match(L),t=b.nodeType;if(S.POS.test(a))return e(a,b,c,d,r);if(d)g=v.call(d,0);else if(r&&1===r.length){if(s.length>1&&9===t&&!f&&(r=S.ID.exec(s[0]))){if(b=gb.find.ID(r[1],b,f)[0],!b)return c;a=a.slice(s.shift().length)}for(p=(r=N.exec(s[0]))&&!r.index&&b.parentNode||b,q=s.pop(),n=q.split(":not")[0],i=0,j=gb.order.length;j>i;i++)if(o=gb.order[i],r=S[o].exec(n)){if(g=gb.find[o]((r[1]||"").replace(R,""),p,f),null==g)continue;n===q&&(a=a.slice(0,a.length-q.length)+n.replace(S[o],""),a||w.apply(c,v.call(g,0)));break}}if(a)for(h=lb(a,b,f),l=h.dirruns++,null==g&&(g=gb.find.TAG("*",N.test(a)&&b.parentNode||b)),i=0;m=g[i];i++)k=h.runs++,h(m,b)&&c.push(m);return c};p.querySelectorAll&&!function(){var a,b=mb,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=q.matchesSelector||q.mozMatchesSelector||q.webkitMatchesSelector||q.oMatchesSelector||q.msMatchesSelector;_(function(a){a.innerHTML="",a.querySelectorAll("[selected]").length||e.push("\\["+y+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),_(function(a){a.innerHTML="

        ",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+y+"*(?:\"\"|'')"),a.innerHTML="",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),mb=function(a,d,f,g,h){if(!(g||h||e&&e.test(a)))if(9===d.nodeType)try{return w.apply(f,v.call(d.querySelectorAll(a),0)),f}catch(i){}else if(1===d.nodeType&&"object"!==d.nodeName.toLowerCase()){var j=d.getAttribute("id"),k=j||x,l=N.test(a)&&d.parentNode||d;j?k=k.replace(c,"\\$&"):d.setAttribute("id",k);try{return w.apply(f,v.call(l.querySelectorAll(a.replace(J,"[id='"+k+"'] $&")),0)),f}catch(i){}finally{j||d.removeAttribute("id")}}return b(a,d,f,g,h)},g&&(_(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push(gb.match.PSEUDO)}catch(c){}}),f=new RegExp(f.join("|")),fb.matchesSelector=function(b,c){if(c=c.replace(d,"='$1']"),!(ib(b)||f.test(c)||e&&e.test(c)))try{var h=g.call(b,c);if(h||a||b.document&&11!==b.document.nodeType)return h}catch(i){}return fb(c,null,null,[b]).length>0})}(),fb.attr=$.attr,$.find=fb,$.expr=fb.selectors,$.expr[":"]=$.expr.pseudos,$.unique=fb.uniqueSort,$.text=fb.getText,$.isXMLDoc=fb.isXML,$.contains=fb.contains}(a);var Ib=/Until$/,Jb=/^(?:parents|prev(?:Until|All))/,Kb=/^.[^:#\[\.,]*$/,Lb=$.expr.match.needsContext,Mb={children:!0,contents:!0,next:!0,prev:!0};$.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if("string"!=typeof a)return $(a).filter(function(){for(b=0,c=h.length;c>b;b++)if($.contains(h[b],this))return!0});for(g=this.pushStack("","find",a),b=0,c=this.length;c>b;b++)if(d=g.length,$.find(a,this[b],g),b>0)for(e=d;ef;f++)if(g[f]===g[e]){g.splice(e--,1);break}return g},has:function(a){var b,c=$(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if($.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(j(this,a,!1),"not",a)},filter:function(a){return this.pushStack(j(this,a,!0),"filter",a)},is:function(a){return!!a&&("string"==typeof a?Lb.test(a)?$(a,this.context).index(this[0])>=0:$.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=Lb.test(a)||"string"!=typeof a?$(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c.ownerDocument&&c!==b&&11!==c.nodeType;){if(g?g.index(c)>-1:$.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}return f=f.length>1?$.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?"string"==typeof a?$.inArray(this[0],$(a)):$.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c="string"==typeof a?$(a,b):$.makeArray(a&&a.nodeType?[a]:a),d=$.merge(this.get(),c);return this.pushStack(h(c[0])||h(d[0])?d:$.unique(d))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}}),$.fn.andSelf=$.fn.addBack,$.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return $.dir(a,"parentNode")},parentsUntil:function(a,b,c){return $.dir(a,"parentNode",c)},next:function(a){return i(a,"nextSibling")},prev:function(a){return i(a,"previousSibling")},nextAll:function(a){return $.dir(a,"nextSibling")},prevAll:function(a){return $.dir(a,"previousSibling")},nextUntil:function(a,b,c){return $.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return $.dir(a,"previousSibling",c)},siblings:function(a){return $.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return $.sibling(a.firstChild)},contents:function(a){return $.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:$.merge([],a.childNodes)}},function(a,b){$.fn[a]=function(c,d){var e=$.map(this,b,c);return Ib.test(a)||(d=c),d&&"string"==typeof d&&(e=$.filter(d,e)),e=this.length>1&&!Mb[a]?$.unique(e):e,this.length>1&&Jb.test(a)&&(e=e.reverse()),this.pushStack(e,a,V.call(arguments).join(","))}}),$.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),1===b.length?$.find.matchesSelector(b[0],a)?[b[0]]:[]:$.find.matches(a,b)},dir:function(a,c,d){for(var e=[],f=a[c];f&&9!==f.nodeType&&(d===b||1!==f.nodeType||!$(f).is(d));)1===f.nodeType&&e.push(f),f=f[c];return e},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}});var Nb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",Ob=/ jQuery\d+="(?:null|\d+)"/g,Pb=/^\s+/,Qb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Rb=/<([\w:]+)/,Sb=/]","i"),Xb=/^(?:checkbox|radio)$/,Yb=/checked\s*(?:[^=]|=\s*.checked.)/i,Zb=/\/(java|ecma)script/i,$b=/^\s*\s*$/g,_b={option:[1,""],legend:[1,"
        ","
        "],thead:[1,"","
        "],tr:[2,"","
        "],td:[3,"","
        "],col:[2,"","
        "],area:[1,"",""],_default:[0,"",""]},ac=k(P),bc=ac.appendChild(P.createElement("div"));_b.optgroup=_b.option,_b.tbody=_b.tfoot=_b.colgroup=_b.caption=_b.thead,_b.th=_b.td,$.support.htmlSerialize||(_b._default=[1,"X
        ","
        "]),$.fn.extend({text:function(a){return $.access(this,function(a){return a===b?$.text(this):this.empty().append((this[0]&&this[0].ownerDocument||P).createTextNode(a)) -},null,a,arguments.length)},wrapAll:function(a){if($.isFunction(a))return this.each(function(b){$(this).wrapAll(a.call(this,b))});if(this[0]){var b=$(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){for(var a=this;a.firstChild&&1===a.firstChild.nodeType;)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each($.isFunction(a)?function(b){$(this).wrapInner(a.call(this,b))}:function(){var b=$(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=$.isFunction(a);return this.each(function(c){$(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){$.nodeName(this,"body")||$(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(1===this.nodeType||11===this.nodeType)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(1===this.nodeType||11===this.nodeType)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!h(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=$.clean(arguments);return this.pushStack($.merge(a,this),"before",this.selector)}},after:function(){if(!h(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=$.clean(arguments);return this.pushStack($.merge(this,a),"after",this.selector)}},remove:function(a,b){for(var c,d=0;null!=(c=this[d]);d++)(!a||$.filter(a,[c]).length)&&(b||1!==c.nodeType||($.cleanData(c.getElementsByTagName("*")),$.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)for(1===a.nodeType&&$.cleanData(a.getElementsByTagName("*"));a.firstChild;)a.removeChild(a.firstChild);return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return $.clone(this,a,b)})},html:function(a){return $.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return 1===c.nodeType?c.innerHTML.replace(Ob,""):b;if(!("string"!=typeof a||Ub.test(a)||!$.support.htmlSerialize&&Wb.test(a)||!$.support.leadingWhitespace&&Pb.test(a)||_b[(Rb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(Qb,"<$1>");try{for(;e>d;d++)c=this[d]||{},1===c.nodeType&&($.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return h(this[0])?this.length?this.pushStack($($.isFunction(a)?a():a),"replaceWith",a):this:$.isFunction(a)?this.each(function(b){var c=$(this),d=c.html();c.replaceWith(a.call(this,b,d))}):("string"!=typeof a&&(a=$(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;$(this).remove(),b?$(b).before(a):$(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],m=this.length;if(!$.support.checkClone&&m>1&&"string"==typeof j&&Yb.test(j))return this.each(function(){$(this).domManip(a,c,d)});if($.isFunction(j))return this.each(function(e){var f=$(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){if(e=$.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,1===g.childNodes.length&&(g=f),f)for(c=c&&$.nodeName(f,"tr"),h=e.cacheable||m-1;m>i;i++)d.call(c&&$.nodeName(this[i],"table")?l(this[i],"tbody"):this[i],i===h?g:$.clone(g,!0,!0));g=f=null,k.length&&$.each(k,function(a,b){b.src?$.ajax?$.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):$.error("no ajax"):$.globalEval((b.text||b.textContent||b.innerHTML||"").replace($b,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),$.buildFragment=function(a,c,d){var e,f,g,h=a[0];return c=c||P,c=(c[0]||c).ownerDocument||c[0]||c,"undefined"==typeof c.createDocumentFragment&&(c=P),!(1===a.length&&"string"==typeof h&&h.length<512&&c===P&&"<"===h.charAt(0))||Vb.test(h)||!$.support.checkClone&&Yb.test(h)||!$.support.html5Clone&&Wb.test(h)||(f=!0,e=$.fragments[h],g=e!==b),e||(e=c.createDocumentFragment(),$.clean(a,c,e,d),f&&($.fragments[h]=g&&e)),{fragment:e,cacheable:f}},$.fragments={},$.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){$.fn[a]=function(c){var d,e=0,f=[],g=$(c),h=g.length,i=1===this.length&&this[0].parentNode;if((null==i||i&&11===i.nodeType&&1===i.childNodes.length)&&1===h)return g[b](this[0]),this;for(;h>e;e++)d=(e>0?this.clone(!0):this).get(),$(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),$.extend({clone:function(a,b,c){var d,e,f,g;if($.support.html5Clone||$.isXMLDoc(a)||!Wb.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bc.innerHTML=a.outerHTML,bc.removeChild(g=bc.firstChild)),!($.support.noCloneEvent&&$.support.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||$.isXMLDoc(a)))for(n(a,g),d=o(a),e=o(g),f=0;d[f];++f)e[f]&&n(d[f],e[f]);if(b&&(m(a,g),c))for(d=o(a),e=o(g),f=0;d[f];++f)m(d[f],e[f]);return d=e=null,g},clean:function(a,b,c,d){var e,f,g,h,i,j,l,m,n,o,q,r=0,s=[];for(b&&"undefined"!=typeof b.createDocumentFragment||(b=P),f=b===P&∾null!=(g=a[r]);r++)if("number"==typeof g&&(g+=""),g){if("string"==typeof g)if(Tb.test(g)){for(f=f||k(b),l=l||f.appendChild(b.createElement("div")),g=g.replace(Qb,"<$1>"),h=(Rb.exec(g)||["",""])[1].toLowerCase(),i=_b[h]||_b._default,j=i[0],l.innerHTML=i[1]+g+i[2];j--;)l=l.lastChild;if(!$.support.tbody)for(m=Sb.test(g),n="table"!==h||m?""!==i[1]||m?[]:l.childNodes:l.firstChild&&l.firstChild.childNodes,e=n.length-1;e>=0;--e)$.nodeName(n[e],"tbody")&&!n[e].childNodes.length&&n[e].parentNode.removeChild(n[e]);!$.support.leadingWhitespace&&Pb.test(g)&&l.insertBefore(b.createTextNode(Pb.exec(g)[0]),l.firstChild),g=l.childNodes,l=f.lastChild}else g=b.createTextNode(g);g.nodeType?s.push(g):s=$.merge(s,g)}if(l&&(f.removeChild(l),g=l=f=null),!$.support.appendChecked)for(r=0;null!=(g=s[r]);r++)$.nodeName(g,"input")?p(g):"undefined"!=typeof g.getElementsByTagName&&$.grep(g.getElementsByTagName("input"),p);if(c)for(o=function(a){return!a.type||Zb.test(a.type)?d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a):void 0},r=0;null!=(g=s[r]);r++)$.nodeName(g,"script")&&o(g)||(c.appendChild(g),"undefined"!=typeof g.getElementsByTagName&&(q=$.grep($.merge([],g.getElementsByTagName("script")),o),s.splice.apply(s,[r+1,0].concat(q)),r+=q.length));return s},cleanData:function(a,b){for(var c,d,e,f,g=0,h=$.expando,i=$.cache,j=$.support.deleteExpando,k=$.event.special;null!=(e=a[g]);g++)if((b||$.acceptData(e))&&(d=e[h],c=d&&i[d])){if(c.events)for(f in c.events)k[f]?$.event.remove(e,f):$.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,$.deletedIds.push(d))}}}),function(){var a,b;$.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=$.uaMatch(R.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.webkit&&(b.safari=!0),$.browser=b,$.sub=function(){function a(b,c){return new a.fn.init(b,c)}$.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(c,d){return d&&d instanceof $&&!(d instanceof a)&&(d=a(d)),$.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(P);return a}}();var cc,dc,ec,fc=/alpha\([^)]*\)/i,gc=/opacity=([^)]*)/,hc=/^(top|right|bottom|left)$/,ic=/^margin/,jc=new RegExp("^("+_+")(.*)$","i"),kc=new RegExp("^("+_+")(?!px)[a-z%]+$","i"),lc=new RegExp("^([-+])=("+_+")","i"),mc={},nc={position:"absolute",visibility:"hidden",display:"block"},oc={letterSpacing:0,fontWeight:400,lineHeight:1},pc=["Top","Right","Bottom","Left"],qc=["Webkit","O","Moz","ms"],rc=$.fn.toggle;$.fn.extend({css:function(a,c){return $.access(this,function(a,c,d){return d!==b?$.style(a,c,d):$.css(a,c)},a,c,arguments.length>1)},show:function(){return s(this,!0)},hide:function(){return s(this)},toggle:function(a,b){var c="boolean"==typeof a;return $.isFunction(a)&&$.isFunction(b)?rc.apply(this,arguments):this.each(function(){(c?a:r(this))?$(this).show():$(this).hide()})}}),$.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=cc(a,"opacity");return""===c?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":$.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var f,g,h,i=$.camelCase(c),j=a.style;if(c=$.cssProps[i]||($.cssProps[i]=q(j,i)),h=$.cssHooks[c]||$.cssHooks[i],d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];if(g=typeof d,"string"===g&&(f=lc.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat($.css(a,c)),g="number"),!(null==d||"number"===g&&isNaN(d)||("number"!==g||$.cssNumber[i]||(d+="px"),h&&"set"in h&&(d=h.set(a,d,e))===b)))try{j[c]=d}catch(k){}}},css:function(a,c,d,e){var f,g,h,i=$.camelCase(c);return c=$.cssProps[i]||($.cssProps[i]=q(a.style,i)),h=$.cssHooks[c]||$.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=cc(a,c)),"normal"===f&&c in oc&&(f=oc[c]),d||e!==b?(g=parseFloat(f),d||$.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?cc=function(a,b){var c,d,e,f,g=getComputedStyle(a,null),h=a.style;return g&&(c=g[b],""!==c||$.contains(a.ownerDocument.documentElement,a)||(c=$.style(a,b)),kc.test(c)&&ic.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=c,c=g.width,h.width=d,h.minWidth=e,h.maxWidth=f)),c}:P.documentElement.currentStyle&&(cc=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return null==e&&f&&f[b]&&(e=f[b]),kc.test(e)&&!hc.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left="fontSize"===b?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),""===e?"auto":e}),$.each(["height","width"],function(a,b){$.cssHooks[b]={get:function(a,c,d){return c?0!==a.offsetWidth||"none"!==cc(a,"display")?v(a,b,d):$.swap(a,nc,function(){return v(a,b,d)}):void 0},set:function(a,c,d){return t(a,c,d?u(a,b,d,$.support.boxSizing&&"border-box"===$.css(a,"boxSizing")):0)}}}),$.support.opacity||($.cssHooks.opacity={get:function(a,b){return gc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=$.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,b>=1&&""===$.trim(f.replace(fc,""))&&c.removeAttribute&&(c.removeAttribute("filter"),d&&!d.filter)||(c.filter=fc.test(f)?f.replace(fc,e):f+" "+e)}}),$(function(){$.support.reliableMarginRight||($.cssHooks.marginRight={get:function(a,b){return $.swap(a,{display:"inline-block"},function(){return b?cc(a,"marginRight"):void 0})}}),!$.support.pixelPosition&&$.fn.position&&$.each(["top","left"],function(a,b){$.cssHooks[b]={get:function(a,c){if(c){var d=cc(a,b);return kc.test(d)?$(a).position()[b]+"px":d}}}})}),$.expr&&$.expr.filters&&($.expr.filters.hidden=function(a){return 0===a.offsetWidth&&0===a.offsetHeight||!$.support.reliableHiddenOffsets&&"none"===(a.style&&a.style.display||cc(a,"display"))},$.expr.filters.visible=function(a){return!$.expr.filters.hidden(a)}),$.each({margin:"",padding:"",border:"Width"},function(a,b){$.cssHooks[a+b]={expand:function(c){var d,e="string"==typeof c?c.split(" "):[c],f={};for(d=0;4>d;d++)f[a+pc[d]+b]=e[d]||e[d-2]||e[0];return f}},ic.test(a)||($.cssHooks[a+b].set=t)});var sc=/%20/g,tc=/\[\]$/,uc=/\r?\n/g,vc=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,wc=/^(?:select|textarea)/i;$.fn.extend({serialize:function(){return $.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?$.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||wc.test(this.nodeName)||vc.test(this.type))}).map(function(a,b){var c=$(this).val();return null==c?null:$.isArray(c)?$.map(c,function(a){return{name:b.name,value:a.replace(uc,"\r\n")}}):{name:b.name,value:c.replace(uc,"\r\n")}}).get()}}),$.param=function(a,c){var d,e=[],f=function(a,b){b=$.isFunction(b)?b():null==b?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(c===b&&(c=$.ajaxSettings&&$.ajaxSettings.traditional),$.isArray(a)||a.jquery&&!$.isPlainObject(a))$.each(a,function(){f(this.name,this.value)});else for(d in a)x(d,a[d],c,f);return e.join("&").replace(sc,"+")};var xc,yc,zc=/#.*$/,Ac=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Bc=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,Cc=/^(?:GET|HEAD)$/,Dc=/^\/\//,Ec=/\?/,Fc=/)<[^<]*)*<\/script>/gi,Gc=/([?&])_=[^&]*/,Hc=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Ic=$.fn.load,Jc={},Kc={},Lc=["*/"]+["*"];try{xc=Q.href}catch(Mc){xc=P.createElement("a"),xc.href="",xc=xc.href}yc=Hc.exec(xc.toLowerCase())||[],$.fn.load=function(a,c,d){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),$.isFunction(c)?(d=c,c=b):"object"==typeof c&&(f="POST"),$.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?$("
        ").append(a.replace(Fc,"")).find(e):a)}),this},$.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){$.fn[b]=function(a){return this.on(b,a)}}),$.each(["get","post"],function(a,c){$[c]=function(a,d,e,f){return $.isFunction(d)&&(f=f||e,e=d,d=b),$.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),$.extend({getScript:function(a,c){return $.get(a,b,c,"script")},getJSON:function(a,b,c){return $.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?A(a,$.ajaxSettings):(b=a,a=$.ajaxSettings),A(a,b),a},ajaxSettings:{url:xc,isLocal:Bc.test(yc[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Lc},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":$.parseJSON,"text xml":$.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:y(Jc),ajaxTransport:y(Kc),ajax:function(a,c){function d(a,c,d,g){var j,l,s,t,v,x=c;2!==u&&(u=2,i&&clearTimeout(i),h=b,f=g||"",w.readyState=a>0?4:0,d&&(t=B(m,w,d)),a>=200&&300>a||304===a?(m.ifModified&&(v=w.getResponseHeader("Last-Modified"),v&&($.lastModified[e]=v),v=w.getResponseHeader("Etag"),v&&($.etag[e]=v)),304===a?(x="notmodified",j=!0):(j=C(m,t),x=j.state,l=j.data,s=j.error,j=!s)):(s=x,(!x||a)&&(x="error",0>a&&(a=0))),w.status=a,w.statusText=""+(c||x),j?p.resolveWith(n,[l,x,w]):p.rejectWith(n,[w,x,s]),w.statusCode(r),r=b,k&&o.trigger("ajax"+(j?"Success":"Error"),[w,m,j?l:s]),q.fireWith(n,[w,x]),k&&(o.trigger("ajaxComplete",[w,m]),--$.active||$.event.trigger("ajaxStop")))}"object"==typeof a&&(c=a,a=b),c=c||{};var e,f,g,h,i,j,k,l,m=$.ajaxSetup({},c),n=m.context||m,o=n!==m&&(n.nodeType||n instanceof $)?$(n):$.event,p=$.Deferred(),q=$.Callbacks("once memory"),r=m.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,setRequestHeader:function(a,b){if(!u){var c=a.toLowerCase();a=t[c]=t[c]||a,s[a]=b}return this},getAllResponseHeaders:function(){return 2===u?f:null},getResponseHeader:function(a){var c;if(2===u){if(!g)for(g={};c=Ac.exec(f);)g[c[1].toLowerCase()]=c[2];c=g[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return u||(m.mimeType=a),this},abort:function(a){return a=a||v,h&&h.abort(a),d(0,a),this}};if(p.promise(w),w.success=w.done,w.error=w.fail,w.complete=q.add,w.statusCode=function(a){if(a){var b;if(2>u)for(b in a)r[b]=[r[b],a[b]];else b=a[w.status],w.always(b)}return this},m.url=((a||m.url)+"").replace(zc,"").replace(Dc,yc[1]+"//"),m.dataTypes=$.trim(m.dataType||"*").toLowerCase().split(bb),null==m.crossDomain&&(j=Hc.exec(m.url.toLowerCase()),m.crossDomain=!(!j||j[1]==yc[1]&&j[2]==yc[2]&&(j[3]||("http:"===j[1]?80:443))==(yc[3]||("http:"===yc[1]?80:443)))),m.data&&m.processData&&"string"!=typeof m.data&&(m.data=$.param(m.data,m.traditional)),z(Jc,m,c,w),2===u)return w;if(k=m.global,m.type=m.type.toUpperCase(),m.hasContent=!Cc.test(m.type),k&&0===$.active++&&$.event.trigger("ajaxStart"),!m.hasContent&&(m.data&&(m.url+=(Ec.test(m.url)?"&":"?")+m.data,delete m.data),e=m.url,m.cache===!1)){var x=$.now(),y=m.url.replace(Gc,"$1_="+x);m.url=y+(y===m.url?(Ec.test(m.url)?"&":"?")+"_="+x:"")}(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",m.contentType),m.ifModified&&(e=e||m.url,$.lastModified[e]&&w.setRequestHeader("If-Modified-Since",$.lastModified[e]),$.etag[e]&&w.setRequestHeader("If-None-Match",$.etag[e])),w.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+Lc+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)w.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(n,w,m)===!1||2===u))return w.abort();v="abort";for(l in{success:1,error:1,complete:1})w[l](m[l]);if(h=z(Kc,m,c,w)){w.readyState=1,k&&o.trigger("ajaxSend",[w,m]),m.async&&m.timeout>0&&(i=setTimeout(function(){w.abort("timeout")},m.timeout));try{u=1,h.send(s,d)}catch(A){if(!(2>u))throw A;d(-1,A)}}else d(-1,"No Transport");return w},active:0,lastModified:{},etag:{}});var Nc=[],Oc=/\?/,Pc=/(=)\?(?=&|$)|\?\?/,Qc=$.now();$.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Nc.pop()||$.expando+"_"+Qc++;return this[a]=!0,a}}),$.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&Pc.test(j),m=k&&!l&&"string"==typeof i&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&Pc.test(i);return"jsonp"===c.dataTypes[0]||l||m?(f=c.jsonpCallback=$.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(Pc,"$1"+f):m?c.data=i.replace(Pc,"$1"+f):k&&(c.url+=(Oc.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||$.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,Nc.push(f)),h&&$.isFunction(g)&&g(h[0]),h=g=b}),"script"):void 0}),$.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return $.globalEval(a),a}}}),$.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),$.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=P.head||P.getElementsByTagName("head")[0]||P.documentElement;return{send:function(e,f){c=P.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){(e||!c.readyState||/loaded|complete/.test(c.readyState))&&(c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||f(200,"success"))},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var Rc,Sc=a.ActiveXObject?function(){for(var a in Rc)Rc[a](0,1)}:!1,Tc=0;$.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&D()||E()}:D,function(a){$.extend($.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}($.ajaxSettings.xhr()),$.support.ajax&&$.ajaxTransport(function(c){if(!c.crossDomain||$.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();if(c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async),c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),c.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||4===i.readyState))if(d=b,g&&(i.onreadystatechange=$.noop,Sc&&delete Rc[g]),e)4!==i.readyState&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}h||!c.isLocal||c.crossDomain?1223===h&&(h=204):h=l.text?200:404}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?4===i.readyState?setTimeout(d,0):(g=++Tc,Sc&&(Rc||(Rc={},$(a).unload(Sc)),Rc[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var Uc,Vc,Wc=/^(?:toggle|show|hide)$/,Xc=new RegExp("^(?:([-+])=|)("+_+")([a-z%]*)$","i"),Yc=/queueHooks$/,Zc=[J],$c={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=Xc.exec(b),h=f.cur(),i=+h||0,j=1;if(g){if(c=+g[2],d=g[3]||($.cssNumber[a]?"":"px"),"px"!==d&&i){i=$.css(f.elem,a,!0)||c||1;do e=j=j||".5",i/=j,$.style(f.elem,a,i+d),j=f.cur()/h;while(1!==j&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};$.Animation=$.extend(H,{tweener:function(a,b){$.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],$c[c]=$c[c]||[],$c[c].unshift(b)},prefilter:function(a,b){b?Zc.unshift(a):Zc.push(a)}}),$.Tween=K,K.prototype={constructor:K,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||($.cssNumber[c]?"":"px")},cur:function(){var a=K.propHooks[this.prop];return a&&a.get?a.get(this):K.propHooks._default.get(this)},run:function(a){var b,c=K.propHooks[this.prop];return this.pos=b=$.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration),this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):K.propHooks._default.set(this),this}},K.prototype.init.prototype=K.prototype,K.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=$.css(a.elem,a.prop,!1,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){$.fx.step[a.prop]?$.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[$.cssProps[a.prop]]||$.cssHooks[a.prop])?$.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},K.propHooks.scrollTop=K.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},$.each(["toggle","show","hide"],function(a,b){var c=$.fn[b];$.fn[b]=function(d,e,f){return null==d||"boolean"==typeof d||!a&&$.isFunction(d)&&$.isFunction(e)?c.apply(this,arguments):this.animate(L(b,!0),d,e,f)}}),$.fn.extend({fadeTo:function(a,b,c,d){return this.filter(r).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=$.isEmptyObject(a),f=$.speed(b,c,d),g=function(){var b=H(this,$.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return"string"!=typeof a&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=null!=a&&a+"queueHooks",f=$.timers,g=$._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&Yc.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem!==this||null!=a&&f[c].queue!==a||(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&$.dequeue(this,a)})}}),$.each({slideDown:L("show"),slideUp:L("hide"),slideToggle:L("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){$.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),$.speed=function(a,b,c){var d=a&&"object"==typeof a?$.extend({},a):{complete:c||!c&&b||$.isFunction(a)&&a,duration:a,easing:c&&b||b&&!$.isFunction(b)&&b};return d.duration=$.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in $.fx.speeds?$.fx.speeds[d.duration]:$.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){$.isFunction(d.old)&&d.old.call(this),d.queue&&$.dequeue(this,d.queue)},d},$.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},$.timers=[],$.fx=K.prototype.init,$.fx.tick=function(){for(var a,b=$.timers,c=0;c-1,l={},m={};k?(m=g.position(),e=m.top,f=m.left):(e=parseFloat(i)||0,f=parseFloat(j)||0),$.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(l.top=b.top-h.top+e),null!=b.left&&(l.left=b.left-h.left+f),"using"in b?b.using.call(a,l):g.css(l)}},$.fn.extend({position:function(){if(this[0]){var a=this[0],b=this.offsetParent(),c=this.offset(),d=_c.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat($.css(a,"marginTop"))||0,c.left-=parseFloat($.css(a,"marginLeft"))||0,d.top+=parseFloat($.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat($.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||P.body;a&&!_c.test(a.nodeName)&&"static"===$.css(a,"position");)a=a.offsetParent;return a||P.body})}}),$.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);$.fn[a]=function(e){return $.access(this,function(a,e,f){var g=M(a);return f===b?g?c in g?g[c]:g.document.documentElement[e]:a[e]:void(g?g.scrollTo(d?$(g).scrollLeft():f,d?f:$(g).scrollTop()):a[e]=f)},a,e,arguments.length,null)}}),$.each({Height:"height",Width:"width"},function(a,c){$.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){$.fn[e]=function(e,f){var g=arguments.length&&(d||"boolean"!=typeof e),h=d||(e===!0||f===!0?"margin":"border");return $.access(this,function(c,d,e){var f;return $.isWindow(c)?c.document.documentElement["client"+a]:9===c.nodeType?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?$.css(c,d,e,h):$.style(c,d,e,h)},c,g?e:b,g)}})}),a.jQuery=a.$=$,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return $})}(window),function(a,b){function c(b,c){var e,f,g,h=b.nodeName.toLowerCase();return"area"===h?(e=b.parentNode,f=e.name,b.href&&f&&"map"===e.nodeName.toLowerCase()?(g=a("img[usemap=#"+f+"]")[0],!!g&&d(g)):!1):(/input|select|textarea|button|object/.test(h)?!b.disabled:"a"===h?b.href||c:c)&&d(b)}function d(b){return a.expr.filters.visible(b)&&!a(b).parents().addBack().filter(function(){return"hidden"===a.css(this,"visibility")}).length}var e=0,f=/^ui-id-\d+$/;a.ui=a.ui||{},a.extend(a.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),a.fn.extend({focus:function(b){return function(c,d){return"number"==typeof c?this.each(function(){var b=this;setTimeout(function(){a(b).focus(),d&&d.call(b)},c)}):b.apply(this,arguments)}}(a.fn.focus),scrollParent:function(){var b;return b=a.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.css(this,"position"))&&/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length)for(var d,e,f=a(this[0]);f.length&&f[0]!==document;){if(d=f.css("position"),("absolute"===d||"relative"===d||"fixed"===d)&&(e=parseInt(f.css("zIndex"),10),!isNaN(e)&&0!==e))return e;f=f.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})},removeUniqueId:function(){return this.each(function(){f.test(this.id)&&a(this).removeAttr("id")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function e(b,c,d,e){return a.each(f,function(){c-=parseFloat(a.css(b,"padding"+this))||0,d&&(c-=parseFloat(a.css(b,"border"+this+"Width"))||0),e&&(c-=parseFloat(a.css(b,"margin"+this))||0)}),c}var f="Width"===d?["Left","Right"]:["Top","Bottom"],g=d.toLowerCase(),h={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?h["inner"+d].call(this):this.each(function(){a(this).css(g,e(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return"number"!=typeof b?h["outer"+d].call(this,b):this.each(function(){a(this).css(g,e(this,b,!0,c)+"px")})}}),a.fn.addBack||(a.fn.addBack=function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}),a("").data("a-b","a").removeData("a-b").data("a-b")&&(a.fn.removeData=function(b){return function(c){return arguments.length?b.call(this,a.camelCase(c)):b.call(this)}}(a.fn.removeData)),a.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),a.support.selectstart="onselectstart"in document.createElement("div"),a.fn.extend({disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e,f=a.ui[b].prototype;for(e in d)f.plugins[e]=f.plugins[e]||[],f.plugins[e].push([c,d[e]])},call:function(a,b,c){var d,e=a.plugins[b];if(e&&a.element[0].parentNode&&11!==a.element[0].parentNode.nodeType)for(d=0;d0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)}})}(jQuery),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i={},j=b.split(".")[0]; -b=b.split(".")[1],e=j+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[j]=a[j]||{},f=a[j][b],g=a[j][b]=function(a,b){return this._createWidget?void(arguments.length&&this._createWidget(a,b)):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,d){return a.isFunction(d)?void(i[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},e=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=e,b=d.apply(this,arguments),this._super=c,this._superApply=f,b}}()):void(i[b]=d)}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},i,{constructor:g,namespace:j,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasOwnProperty(e)&&f!==b&&(c[e]=a.isPlainObject(f)?a.isPlainObject(c[e])?a.widget.extend({},c[e],f):a.widget.extend({},f):f);return c},a.widget.bridge=function(c,e){var f=e.prototype.widgetFullName||c;a.fn[c]=function(g){var h="string"==typeof g,i=d.call(arguments,1),j=this;return g=!h&&i.length?a.widget.extend.apply(null,[g].concat(i)):g,this.each(h?function(){var d,e=a.data(this,f);return e?a.isFunction(e[g])&&"_"!==g.charAt(0)?(d=e[g].apply(e,i),d!==e&&d!==b?(j=d&&d.jquery?j.pushStack(d.get()):d,!1):void 0):a.error("no such method '"+g+"' for "+c+" widget instance"):a.error("cannot call methods on "+c+" prior to initialization; attempted to call method '"+g+"'")}:function(){var b=a.data(this,f);b?b.option(g||{})._init():a.data(this,f,new e(g,this))}),j}},a.Widget=function(){},a.Widget._childConstructors=[],a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
        ",options:{disabled:!1,create:null},_createWidget:function(b,d){d=a(d||this.defaultElement||this)[0],this.element=a(d),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),d!==this&&(a.data(d,this.widgetFullName,this),this._on(!0,this.element,{remove:function(a){a.target===d&&this.destroy()}}),this.document=a(d.style?d.ownerDocument:d.document||d),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:a.noop,_getCreateEventData:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(a.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e,f,g,h=c;if(0===arguments.length)return a.widget.extend({},this.options);if("string"==typeof c)if(h={},e=c.split("."),c=e.shift(),e.length){for(f=h[c]=a.widget.extend({},this.options[c]),g=0;g=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(a){function b(a,b,c){return a>b&&b+c>a}function c(a){return/left|right/.test(a.css("float"))||/inline|table-cell/.test(a.css("display"))}a.widget("ui.sortable",a.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===a.axis||c(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){"disabled"===b?(this.options[b]=c,this.widget().toggleClass("ui-sortable-disabled",!!c)):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=null,e=!1,f=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(b),a(b.target).parents().each(function(){return a.data(this,f.widgetName+"-item")===f?(d=a(this),!1):void 0}),a.data(b.target,f.widgetName+"-item")===f&&(d=a(b.target)),d&&(!this.options.handle||c||(a(this.options.handle,d).find("*").addBack().each(function(){this===b.target&&(e=!0)}),e))?(this.currentItem=d,this._removeCurrentsFromItems(),!0):!1)},_mouseStart:function(b,c,d){var e,f,g=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,g.cursorAt&&this._adjustOffsetFromHelper(g.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),g.containment&&this._setContainment(),g.cursor&&"auto"!==g.cursor&&(f=this.document.find("body"),this.storedCursor=f.css("cursor"),f.css("cursor",g.cursor),this.storedStylesheet=a("").appendTo(f)),g.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",g.opacity)),g.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",g.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!d)for(e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("activate",b,this._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!g.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){var c,d,e,f,g=this.options,h=!1;for(this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;c--)if(d=this.items[c],e=d.item[0],f=this._intersectsWithPointer(d),f&&d.instance===this.currentContainer&&e!==this.currentItem[0]&&this.placeholder[1===f?"next":"prev"]()[0]!==e&&!a.contains(this.placeholder[0],e)&&("semi-dynamic"===this.options.type?!a.contains(this.element[0],e):!0)){if(this.direction=1===f?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(d))break;this._rearrange(b,d),this._trigger("change",b,this._uiHash());break}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(b){if(a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b),this.options.revert){var d=this,e=this.placeholder.offset(),f=this.options.axis,g={};f&&"x"!==f||(g.left=e.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),f&&"y"!==f||(g.top=e.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,a(this.helper).animate(g,parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--)this.containers[b]._trigger("deactivate",null,this._uiHash(this)),this.containers[b].containerCache.over&&(this.containers[b]._trigger("out",null,this._uiHash(this)),this.containers[b].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[\-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l="x"===this.options.axis||d+j>h&&i>d+j,m="y"===this.options.axis||b+k>f&&g>b+k,n=l&&m;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?n:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return 0!==a&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor===String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c,d,e,f,g=[],h=[],i=this._connectWith();if(i&&b)for(c=i.length-1;c>=0;c--)for(e=a(i[c]),d=e.length-1;d>=0;d--)f=a.data(e[d],this.widgetFullName),f&&f!==this&&!f.options.disabled&&h.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),f]);for(h.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),c=h.length-1;c>=0;c--)h[c][0].each(function(){g.push(this)});return a(g)},_removeCurrentsFromItems:function(){var b=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=a.grep(this.items,function(a){for(var c=0;c=0;c--)for(e=a(m[c]),d=e.length-1;d>=0;d--)f=a.data(e[d],this.widgetFullName),f&&f!==this&&!f.options.disabled&&(l.push([a.isFunction(f.options.items)?f.options.items.call(f.element[0],b,{item:this.currentItem}):a(f.options.items,f.element),f]),this.containers.push(f));for(c=l.length-1;c>=0;c--)for(g=l[c][1],h=l[c][0],d=0,j=h.length;j>d;d++)i=a(h[d]),i.data(this.widgetName+"-item",g),k.push({item:i,instance:g,width:0,height:0,left:0,top:0})},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var c,d,e,f;for(c=this.items.length-1;c>=0;c--)d=this.items[c],d.instance!==this.currentContainer&&this.currentContainer&&d.item[0]!==this.currentItem[0]||(e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item,b||(d.width=e.outerWidth(),d.height=e.outerHeight()),f=e.offset(),d.left=f.left,d.top=f.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(c=this.containers.length-1;c>=0;c--)f=this.containers[c].element.offset(),this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight();return this},_createPlaceholder:function(b){b=b||this;var c,d=b.options;d.placeholder&&d.placeholder.constructor!==String||(c=d.placeholder,d.placeholder={element:function(){var d=b.currentItem[0].nodeName.toLowerCase(),e=a("<"+d+">",b.document[0]).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===d?b.currentItem.children().each(function(){a("
        ",b.document[0]).attr("colspan",a(this).attr("colspan")||1).appendTo(e)}):"img"===d&&e.attr("src",b.currentItem.attr("src")),c||e.css("visibility","hidden"),e},update:function(a,e){(!c||d.forcePlaceholderSize)&&(e.height()||e.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10)),e.width()||e.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10)))}}),b.placeholder=a(d.placeholder.element.call(b.element,b.currentItem)),b.currentItem.after(b.placeholder),d.placeholder.update(b,b.placeholder)},_contactContainers:function(d){var e,f,g,h,i,j,k,l,m,n,o=null,p=null;for(e=this.containers.length-1;e>=0;e--)if(!a.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(o&&a.contains(this.containers[e].element[0],o.element[0]))continue;o=this.containers[e],p=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",d,this._uiHash(this)),this.containers[e].containerCache.over=0);if(o)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",d,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(g=1e4,h=null,n=o.floating||c(this.currentItem),i=n?"left":"top",j=n?"width":"height",k=this.positionAbs[i]+this.offset.click[i],f=this.items.length-1;f>=0;f--)a.contains(this.containers[p].element[0],this.items[f].item[0])&&this.items[f].item[0]!==this.currentItem[0]&&(!n||b(this.positionAbs.top+this.offset.click.top,this.items[f].top,this.items[f].height))&&(l=this.items[f].item.offset()[i],m=!1,Math.abs(l-k)>Math.abs(l+this.items[f][j]-k)&&(m=!0,l+=this.items[f][j]),Math.abs(l-k)this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top)),e.grid&&(c=this.originalPageY+Math.round((g-this.originalPageY)/e.grid[1])*e.grid[1],g=this.containment?c-this.offset.click.top>=this.containment[1]&&c-this.offset.click.top<=this.containment[3]?c:c-this.offset.click.top>=this.containment[1]?c-e.grid[1]:c+e.grid[1]:c,d=this.originalPageX+Math.round((f-this.originalPageX)/e.grid[0])*e.grid[0],f=this.containment?d-this.offset.click.left>=this.containment[0]&&d-this.offset.click.left<=this.containment[2]?d:d-this.offset.click.left>=this.containment[0]?d-e.grid[0]:d+e.grid[0]:d)),{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():i?0:h.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():i?0:h.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this.counter;this._delay(function(){e===this.counter&&this.refreshPositions(!d)})},_clear:function(a,b){this.reverting=!1;var c,d=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(c in this._storedCSS)("auto"===this._storedCSS[c]||"static"===this._storedCSS[c])&&(this._storedCSS[c]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!b&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||b||d.push(function(a){this._trigger("update",a,this._uiHash())}),this!==this.currentContainer&&(b||(d.push(function(a){this._trigger("remove",a,this._uiHash())}),d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.currentContainer)),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.currentContainer)))),c=this.containers.length-1;c>=0;c--)b||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[c])),this.containers[c].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[c])),this.containers[c].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!b){for(this._trigger("beforeStop",a,this._uiHash()),c=0;c
        ',trigger:"hover",title:"",delay:0,html:!0}}(window.jQuery);var Constants={DEFAULT:{HEIGHT:32,WIDTH:32,FPS:12},MODEL_VERSION:2,MAX_HEIGHT:1024,MAX_WIDTH:1024,MAX_CURRENT_COLORS_DISPLAYED:100,MINIMUM_ZOOM:1,PREVIEW_FILM_SIZE:96,ANIMATED_PREVIEW_WIDTH:200,DEFAULT_PEN_COLOR:"#000000",TRANSPARENT_COLOR:"rgba(0, 0, 0, 0)",OVERLAY_ONION_SKIN:"onion-skin",OVERLAY_LAYER_PREVIEW:"layer-preview",OVERLAY_DISABLED:"no-overlay",NO_PALETTE_ID:"__no-palette",CURRENT_COLORS_PALETTE_ID:"__current-colors",PREFERRED_COLOR_FORMAT:"rgb",SELECTION_TRANSPARENT_COLOR:"rgba(255, 255, 255, 0.6)",TOOL_TARGET_HIGHLIGHT_COLOR:"rgba(255, 255, 255, 0.2)",STATIC:{URL:{SAVE:"http://3.piskel-app.appspot.com/store",GET:"http://3.piskel-app.appspot.com/get"}},APPENGINE:{URL:{SAVE:"save"}},IMAGE_SERVICE_UPLOAD_URL:"http://piskel-imgstore-a.appspot.com/__/upload",IMAGE_SERVICE_GET_URL:"http://piskel-imgstore-a.appspot.com/img/",ZOOMED_OUT_BACKGROUND_COLOR:"#A0A0A0",LEFT_BUTTON:0,MIDDLE_BUTTON:1,RIGHT_BUTTON:2,MOUSEMOVE_THROTTLING:10,ABSTRACT_FUNCTION:function(){throw"abstract method should be implemented"},EMPTY_FUNCTION:function(){},DRAWING_TEST_FOLDER:"drawing"},Events={TOOL_SELECTED:"TOOL_SELECTED",SELECT_TOOL:"SELECT_TOOL",TOOL_RELEASED:"TOOL_RELEASED",SELECT_PRIMARY_COLOR:"SELECT_PRIMARY_COLOR",SELECT_SECONDARY_COLOR:"SELECT_SECONDARY_COLOR",PRIMARY_COLOR_SELECTED:"PRIMARY_COLOR_SELECTED",SECONDARY_COLOR_SELECTED:"SECONDARY_COLOR_SELECTED",CURSOR_MOVED:"CURSOR_MOVED",DRAG_START:"DRAG_START",DRAG_END:"DRAG_END",DIALOG_DISPLAY:"DIALOG_DISPLAY",DIALOG_HIDE:"DIALOG_HIDE",PALETTE_LIST_UPDATED:"PALETTE_LIST_UPDATED",USER_SETTINGS_CHANGED:"USER_SETTINGS_CHANGED",CLOSE_SETTINGS_DRAWER:"CLOSE_SETTINGS_DRAWER",PISKEL_RESET:"PISKEL_RESET",PISKEL_SAVE_STATE:"PISKEL_SAVE_STATE",PISKEL_SAVED:"PISKEL_SAVED",FRAME_SIZE_CHANGED:"FRAME_SIZE_CHANGED",SELECTION_CREATED:"SELECTION_CREATED",SELECTION_MOVE_REQUEST:"SELECTION_MOVE_REQUEST",SELECTION_DISMISSED:"SELECTION_DISMISSED",SHOW_NOTIFICATION:"SHOW_NOTIFICATION",HIDE_NOTIFICATION:"HIDE_NOTIFICATION",ZOOM_CHANGED:"ZOOM_CHANGED",CURRENT_COLORS_UPDATED:"CURRENT_COLORS_UPDATED",MOUSE_EVENT:"MOUSE_EVENT",TEST_RECORD_END:"TEST_RECORD_END",TEST_CASE_END:"TEST_CASE_END",TEST_SUITE_END:"TEST_SUITE_END"};jQuery.namespace=function(){var a,b,c,d=arguments,e=null;for(a=0;a255||b>255||c>255)throw"Invalid color component";return(a<<16|b<<8|c).toString(16)},a.normalize=function(a,b){return"undefined"==typeof a||null===a?b:a},a.inherit=function(a,b){a.prototype=Object.create(b.prototype),a.prototype.constructor=a,a.prototype.superclass=b.prototype},a.wrap=function(a,b){for(var c in b)"function"==typeof b[c]&&"undefined"==typeof a[c]&&(a[c]=b[c].bind(b))};var b={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};a.escapeHtml=function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return b[a]})};var c={};a.unescapeHtml=function(a){return Object.keys(b).forEach(function(d){c[d]=c[d]||new RegExp(b[d],"g"),a=a.replace(c[d],d)}),a}}(),function(){var a=$.namespace("pskl.utils"),b=navigator.userAgent;a.UserAgent={isIE:/MSIE/i.test(b),isIE11:/trident/i.test(b),isChrome:/Chrome/i.test(b),isFirefox:/Firefox/i.test(b),isMac:/Mac/.test(b)},a.UserAgent.version=function(){return pskl.utils.UserAgent.isIE?parseInt(/MSIE\s?(\d+)/i.exec(b)[1],10):pskl.utils.UserAgent.isChrome?parseInt(/Chrome\/(\d+)/i.exec(b)[1],10):pskl.utils.UserAgent.isFirefox?parseInt(/Firefox\/(\d+)/i.exec(b)[1],10):void 0}()}(),function(){var a,b=$.namespace("pskl.utils");Uint8Array&&(a=new Uint8Array([62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,0,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51])),b.Base64={toText:function(a){return window.atob(a.replace(/data\:.*?\;base64\,/,""))},decode:function(b){for(var c,d=0,e=[0,0],f=0,g=0,h=b.length,i=0,j=new Uint8Array(h/4*3|0);h--;){var k=b.charCodeAt(i++),l=a[k-43];255!==l&&l!==c&&(e[1]=e[0],e[0]=k,g=g<<6|l,f++,4===f&&(j[d++]=g>>>16,61!==e[1]&&(j[d++]=g>>>8),61!==e[0]&&(j[d++]=g),f=0))}return j.buffer}}}(),function(){var a=$.namespace("pskl.utils"),b=/\s*;\s*base64\s*(?:;|$)/i;a.BlobUtils={dataToBlob:function(a,c,d){var e,f=a.indexOf(","),g=a.substring(f+1),h=b.test(a.substring(0,f));if(Blob.fake)e=new Blob,e.encoding=h?"base64":"URI",e.data=g,e.size=g.length;else if(Uint8Array){var i=h?pskl.utils.Base64.decode(g):decodeURIComponent(g);e=new Blob([i],{type:c})}d(e)},canvasToBlob:function(a,b,c){if(c=c||"image/png",a.mozGetAsFile)b(a.mozGetAsFile("canvas",c));else{var d=Array.prototype.slice.call(arguments,2),e=a.toDataURL.apply(a,d);pskl.utils.BlobUtils.dataToBlob(e,c,b)}},stringToBlob:function(a,b,c){c=c||"text/plain",pskl.utils.BlobUtils.dataToBlob("data:"+c+","+a,c,b)}}}(),function(){var a=$.namespace("pskl");a.CanvasUtils={createCanvas:function(a,b,c){var d=document.createElement("canvas");if(d.setAttribute("width",a),d.setAttribute("height",b),"string"==typeof c&&(c=[c]),Array.isArray(c))for(var e=0;ea?"0"+a:""+a};a.DateUtils={format:function(a,c){return a=new Date(a),pskl.utils.Template.replace(c,{Y:a.getFullYear(),M:b(a.getMonth()+1),D:b(a.getDate()),H:b(a.getHours()),m:b(a.getMinutes()),s:b(a.getSeconds())})}}}(),function(){var a=$.namespace("pskl.utils");a.Dom={isParent:function(a,b,c){if(a&&b)for(c&&(a=a.parentNode);a;){if(a===b)return!0;a=a.parentNode}return!1},getParentWithData:function(a,b){for(;a;){if(a.dataset&&"undefined"!=typeof a.dataset[b])return a;a=a.parentNode}return null}}}(),function(){var a=$.namespace("pskl.utils");a.Math={minmax:function(a,b,c){return Math.max(Math.min(a,c),b)}}}(),function(){var a=$.namespace("pskl.utils"),b=function(a){a.stopPropagation()};a.FileUtils={readFile:function(a,b){var c=new FileReader;c.onload=function(a){b(a.target.result)},c.readAsDataURL(a)},readImageFile:function(b,c){a.FileUtils.readFile(b,function(a){var b=new Image;b.onload=c.bind(null,b),b.src=a})},downloadAsFile:function(a,c){var d=window.saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator);if(d)d(a,c);else{var e=document.createElement("a");a=window.URL.createObjectURL(a),e.setAttribute("href",a),e.setAttribute("download",c),document.body.appendChild(e),e.addEventListener("click",b),e.click(),e.removeEventListener("click",b),document.body.removeChild(e)}}}}(),function(){var a=$.namespace("pskl.utils"),b={};a.FrameUtils={merge:function(a){var b=null;if(a.length){b=a[0].clone();for(var c=(b.getWidth(),b.getHeight(),1);ce;e++){d[e]=[];for(var f=0;c>f;f++){var g=4*(f*b+e),h=a[g],i=a[g+1],j=a[g+2],k=a[g+3];d[e][f]=125>k?Constants.TRANSPARENT_COLOR:pskl.utils.FrameUtils.rgbToHex(h,i,j)}}return pskl.model.Frame.fromPixelGrid(d)},rgbToHex:function(a,b,c){return"#"+this.componentToHex(a)+this.componentToHex(b)+this.componentToHex(c)},componentToHex:function(a){var b=a.toString(16);return 1==b.length?"0"+b:b},toImage:function(a,b,c){b=b||1,c=c||Constants.TRANSPARENT_COLOR;var d=new pskl.rendering.CanvasRenderer(a,b);return d.drawTransparentAs(c),d.render()}}}(),function(){var a=$.namespace("pskl.utils");a.LayerUtils={createFromImage:function(a,b){var c=a.width,d=a.height,e=c/b,f=pskl.CanvasUtils.createCanvas(c,d),g=f.getContext("2d");g.drawImage(a,0,0,c,d,0,0,c,d);for(var h=[],i=0;b>i;i++){var j=g.getImageData(e*i,0,e,d).data,k=pskl.utils.FrameUtils.createFromImageData(j,e,d);h.push(k)}return h}}}(),function(){var a=$.namespace("pskl.utils");a.ImageResizer={resize:function(a,b,c,d){var e=pskl.CanvasUtils.createCanvas(b,c),f=e.getContext("2d");return f.save(),d||pskl.CanvasUtils.disableImageSmoothing(e),f.translate(e.width/2,e.height/2),f.scale(b/a.width,c/a.height),f.drawImage(a,-a.width/2,-a.height/2),f.restore(),e},resizeNearestNeighbour:function(a,b,c,d){c=c||0;for(var e,f,g=pskl.CanvasUtils.createCanvas(b*a.width,b*a.height),h=g.getContext("2d"),i=pskl.CanvasUtils.getImageDataFromCanvas(a),j={},k=0,l=0,m=0;m0;){k++;var m=g.pop();a.setPixel(m.col,m.row,d),f.push({col:m.col,row:m.row});for(var n=0;4>n;n++){var o=m.col+i[n],p=m.row+h[n];try{a.containsPixel(o,p)&&a.getPixel(o,p)==e&&g.push({col:o,row:p})}catch(j){}}if(k>10*l){console.log("loop breaker called");break}}return f}},calculateZoomForContainer:function(a,b,c){return this.calculateZoom(a.height(),a.width(),b,c)}}}(),function(){var a=$.namespace("pskl.utils");a.PiskelFileUtils={loadFromFile:function(a,b){pskl.utils.FileUtils.readFile(a,function(a){var c=pskl.utils.Base64.toText(a),d=JSON.parse(c),e=d.piskel.fps,f=new pskl.model.piskel.Descriptor(d.piskel.name,d.piskel.description,!0);pskl.utils.serialization.Deserializer.deserialize(d,function(a){b(a,f,e)})})}}}(),function(){var a=$.namespace("pskl.utils"),b={};a.Template={get:function(a){if(!b[a]){var c=document.getElementById(a);c?b[a]=c.innerHTML:console.error("Could not find template for id :",a)}return b[a]},createFromHTML:function(a){var b=document.createElement("div");return b.innerHTML=a,b.children[0]},getAndReplace:function(a,b){var c="",d=pskl.utils.Template.get(a);return d&&(c=pskl.utils.Template.replace(d,b)),c},replace:function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=b[c];-1!==c.indexOf(":")&&(d===!0?d=c.split(":")[1]:d===!1&&(d="")),a=a.replace(new RegExp("\\{\\{"+c+"\\}\\}","g"),d)}return a}}}(),function(){var a=$.namespace("pskl");a.UserSettings={GRID_WIDTH:"GRID_WIDTH",CANVAS_BACKGROUND:"CANVAS_BACKGROUND",SELECTED_PALETTE:"SELECTED_PALETTE",TILED_PREVIEW:"TILED_PREVIEW",ONION_SKIN:"ONION_SKIN",LAYER_PREVIEW:"LAYER_PREVIEW",KEY_TO_DEFAULT_VALUE_MAP_:{GRID_WIDTH:0,CANVAS_BACKGROUND:"lowcont-dark-canvas-background",SELECTED_PALETTE:Constants.CURRENT_COLORS_PALETTE_ID,TILED_PREVIEW:!1,ONION_SKIN:!1,LAYER_PREVIEW:!0},cache_:{},get:function(a){if(this.checkKeyValidity_(a),!(a in this.cache_)){var b=this.readFromLocalStorage_(a);this.cache_[a]="undefined"!=typeof b&&null!==b?b:this.readFromDefaults_(a)}return this.cache_[a]},set:function(a,b){this.checkKeyValidity_(a),this.cache_[a]=b,this.writeToLocalStorage_(a,b),$.publish(Events.USER_SETTINGS_CHANGED,[a,b])},readFromLocalStorage_:function(a){var b=window.localStorage[a];return"undefined"!=typeof b&&(b=JSON.parse(b)),b},writeToLocalStorage_:function(a,b){window.localStorage[a]=JSON.stringify(b)},readFromDefaults_:function(a){return this.KEY_TO_DEFAULT_VALUE_MAP_[a]},checkKeyValidity_:function(a){a in this.KEY_TO_DEFAULT_VALUE_MAP_||console.log("UserSettings key <"+a+"> not find in supported keys.")}}}(),function(){var a=$.namespace("pskl.utils"),b=function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)};a.Uuid={generate:function(){return"ss-s-s-s-sss".replace(/s/g,function(){return b()})}}}(),function(){var a=$.namespace("pskl.utils");a.Xhr={get:function(b,c,d){var e=a.Xhr.xhr_(b,"GET",c,d);e.send()},post:function(b,c,d,e){var f=a.Xhr.xhr_(b,"POST",d,e),g=new FormData;if("object"==typeof c)for(var h in c)c.hasOwnProperty(h)&&g.append(h,c[h]);f.send(g)},xhr_:function(a,b,c,d){c=c||function(){},d=d||function(){};var e=new XMLHttpRequest;return e.open(b,a,!0),e.onload=function(a){200==this.status?c(this):this.onerror(this,a)},e.onerror=function(a){d(a)},e}}}(),function(){var a=$.namespace("pskl.utils");a.Serializer={serializePiskel:function(a,b){var c=a.getLayers().map(function(a){return pskl.utils.Serializer.serializeLayer(a,b)});return JSON.stringify({modelVersion:Constants.MODEL_VERSION,piskel:{name:a.getDescriptor().name,description:a.getDescriptor().description,fps:pskl.app.piskelController.getFPS(),height:a.getHeight(),width:a.getWidth(),layers:c,expanded:b}})},serializeLayer:function(a,b){var c=a.getFrames(),d=new pskl.rendering.FramesheetRenderer(c),e={name:a.getName(),frameCount:c.length};return b?(e.grids=c.map(function(a){return a.pixels}),e):(e.base64PNG=d.renderAsCanvas().toDataURL(),JSON.stringify(e))}}}(),function(){var a=$.namespace("pskl.utils.serialization");a.Deserializer=function(a,b){this.layersToLoad_=0,this.data_=a,this.callback_=b,this.piskel_=null},a.Deserializer.deserialize=function(b,c){var d;d=b.modelVersion==Constants.MODEL_VERSION?new a.Deserializer(b,c):1==b.modelVersion?new a.backward.Deserializer_v1(b,c):new a.backward.Deserializer_v0(b,c),d.deserialize()},a.Deserializer.prototype.deserialize=function(a){var b=this.data_,c=b.piskel;a=a||"Deserialized piskel";var d=new pskl.model.piskel.Descriptor(a,"");this.piskel_=new pskl.model.Piskel(c.width,c.height,d),this.layersToLoad_=c.layers.length,c.layers.forEach(c.expanded?this.loadExpandedLayer.bind(this):this.deserializeLayer.bind(this))},a.Deserializer.prototype.deserializeLayer=function(a){var b=JSON.parse(a),c=new pskl.model.Layer(b.name),d=b.base64PNG,e=new Image;return e.onload=function(){var a=pskl.utils.LayerUtils.createFromImage(e,b.frameCount);this.addFramesToLayer(a,c)}.bind(this),e.src=d,c},a.Deserializer.prototype.loadExpandedLayer=function(a){var b=new pskl.model.Layer(a.name),c=a.grids.map(function(a){return pskl.model.Frame.fromPixelGrid(a)});return this.addFramesToLayer(c,b),b},a.Deserializer.prototype.addFramesToLayer=function(a,b){a.forEach(b.addFrame.bind(b)),this.piskel_.addLayer(b),this.onLayerLoaded_()},a.Deserializer.prototype.onLayerLoaded_=function(){this.layersToLoad_=this.layersToLoad_-1,0===this.layersToLoad_&&this.callback_(this.piskel_)}}(),function(){var a=$.namespace("pskl.utils.serialization.backward");a.Deserializer_v0=function(a,b){this.data_=a,this.callback_=b},a.Deserializer_v0.prototype.deserialize=function(){var a=this.data_,b=a.map(function(a){return pskl.model.Frame.fromPixelGrid(a)}),c=new pskl.model.piskel.Descriptor("Deserialized piskel",""),d=pskl.model.Layer.fromFrames("Layer 1",b);this.callback_(pskl.model.Piskel.fromLayers([d],c))}}(),function(){var a=$.namespace("pskl.utils.serialization.backward");a.Deserializer_v1=function(a,b){this.callback_=b,this.data_=a},a.Deserializer_v1.prototype.deserialize=function(){var a=this.data_.piskel,b=new pskl.model.piskel.Descriptor("Deserialized piskel",""),c=new pskl.model.Piskel(a.width,a.height,b);a.layers.forEach(function(a){var b=this.deserializeLayer(a);c.addLayer(b)}.bind(this)),this.callback_(c)},a.Deserializer_v1.prototype.deserializeLayer=function(a){var b=JSON.parse(a),c=new pskl.model.Layer(b.name);return b.frames.forEach(function(a){var b=this.deserializeFrame(a);c.addFrame(b)}.bind(this)),c},a.Deserializer_v1.prototype.deserializeFrame=function(a){var b=JSON.parse(a);return pskl.model.Frame.fromPixelGrid(b)}}(),function(){var a=function(){(function(){function a(b,c){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var d=a.resolve(b);if(!d)throw new Error("Failed to resolve module "+b);var e={id:b,require:a,filename:b,exports:{},loaded:!1,parent:c,children:[]};c&&c.children.push(e);var f=b.slice(0,b.lastIndexOf("/")+1);return a.cache[b]=e.exports,d.call(e.exports,e,e.exports,f,b),e.loaded=!0,a.cache[b]=e.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define("/gif.worker.coffee",function(b){var c,d;c=a("/GIFEncoder.js",b),d=function(a){var b,d,e,f;return b=new c(a.width,a.height),0===a.index?b.writeHeader():b.firstFrame=!1,b.setTransparent(a.transparent),b.setRepeat(a.repeat),b.setDelay(a.delay),b.setQuality(a.quality),b.setPreserveColors(a.preserveColors),b.addFrame(a.data),a.last&&b.finish(),e=b.stream(),a.data=e.pages,a.cursor=e.cursor,a.pageSize=e.constructor.pageSize,a.canTransfer?(f=function(b){for(var c=0,e=a.data.length;e>c;++c)d=a.data[c],b.push(d.buffer);return b}.call(this,[]),self.postMessage(a,f)):self.postMessage(a)},self.onmessage=function(a){return d(a.data)}}),a.define("/GIFEncoder.js",function(b){function c(){this.page=-1,this.pages=[],this.newPage()}function d(a,b){this.width=~~a,this.height=~~b,this.transparent=null,this.transIndex=0,this.repeat=-1,this.delay=0,this.image=null,this.pixels=null,this.indexedPixels=null,this.colorDepth=null,this.colorTab=null,this.usedEntry=new Array,this.palSize=7,this.dispose=-1,this.firstFrame=!0,this.sample=10,this.preserveColors=!1,this.out=new c}var e=a("/TypedNeuQuant.js",b),f=a("/SimpleQuant.js",b),g=a("/LZWEncoder.js",b);c.pageSize=4096,c.charMap={};for(var h=0;256>h;h++)c.charMap[h]=String.fromCharCode(h);c.prototype.newPage=function(){this.pages[++this.page]=new Uint8Array(c.pageSize),this.cursor=0},c.prototype.getData=function(){for(var a="",b=0;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(a){for(var b=a.length,c=0;b>c;c++)this.writeByte(a.charCodeAt(c))},c.prototype.writeBytes=function(a,b,c){for(var d=c||a.length,e=b||0;d>e;e++)this.writeByte(a[e])},d.prototype.setDelay=function(a){this.delay=Math.round(a/10)},d.prototype.setFrameRate=function(a){this.delay=Math.round(100/a)},d.prototype.setDispose=function(a){a>=0&&(this.dispose=a)},d.prototype.setRepeat=function(a){this.repeat=a},d.prototype.setTransparent=function(a){this.transparent=a},d.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},d.prototype.finish=function(){this.out.writeByte(59)},d.prototype.setQuality=function(a){1>a&&(a=1),this.sample=a},d.prototype.setPreserveColors=function(a){this.preserveColors=a},d.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")},d.prototype.analyzePixels=function(){var a=this.pixels.length,b=a/3;this.indexedPixels=new Uint8Array(b);var c;c=this.preserveColors?new f(this.pixels,this.sample):new e(this.pixels,this.sample),c.buildColormap(),this.colorTab=c.getColormap();for(var d=0,g=0;b>g;g++){var h=c.lookupRGB(255&this.pixels[d++],255&this.pixels[d++],255&this.pixels[d++]);this.usedEntry[h]=!0,this.indexedPixels[g]=h}this.pixels=null,this.colorDepth=8,this.palSize=7,null!==this.transparent&&(this.transIndex=this.findClosest(this.transparent))},d.prototype.findClosest=function(a){if(null===this.colorTab)return-1;for(var b=(16711680&a)>>16,c=(65280&a)>>8,d=255&a,e=0,f=16777216,g=this.colorTab.length,h=0;g>h;){var i=b-(255&this.colorTab[h++]),j=c-(255&this.colorTab[h++]),k=d-(255&this.colorTab[h]),l=i*i+j*j+k*k,m=parseInt(h/3);this.usedEntry[m]&&f>l&&(f=l,e=m),h++}return e},d.prototype.getImagePixels=function(){var a=this.width,b=this.height;this.pixels=new Uint8Array(a*b*3);for(var c=this.image,d=0,e=0;b>e;e++)for(var f=0;a>f;f++){var g=e*a*4+4*f;this.pixels[d++]=c[g],this.pixels[d++]=c[g+1],this.pixels[d++]=c[g+2]}},d.prototype.writeGraphicCtrlExt=function(){this.out.writeByte(33),this.out.writeByte(249),this.out.writeByte(4);var a,b;null===this.transparent?(a=0,b=0):(a=1,b=2),this.dispose>=0&&(b=7&dispose),b<<=2,this.out.writeByte(0|b|0|a),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},d.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(this.firstFrame?0:128|this.palSize)},d.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},d.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes("NETSCAPE2.0"),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},d.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);for(var a=768-this.colorTab.length,b=0;a>b;b++)this.out.writeByte(0)},d.prototype.writeShort=function(a){this.out.writeByte(255&a),this.out.writeByte(a>>8&255)},d.prototype.writePixels=function(){var a=new g(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},d.prototype.stream=function(){return this.out},b.exports=d}),a.define("/LZWEncoder.js",function(a){function b(a,b,g,h){function i(a,b){y[s++]=a,s>=254&&n(b)}function j(a){k(e),C=v+2,D=!0,q(v,a)}function k(a){for(var b=0;a>b;++b)z[b]=-1}function l(a,b){var f,g,h,i,l,m,n;for(u=a,D=!1,n_bits=u,t=o(n_bits),v=1<f;f*=2)++n;n=8-n,m=e,k(m),q(v,b);a:for(;(g=p())!=c;)if(f=(g<=0){l=m-h,0===h&&(l=1);do if((h-=l)<0&&(h+=m),z[h]===f){i=A[h];continue a}while(z[h]>=0)}q(i,b),i=g,1<C?(A[h]=C++,z[h]=f):j(b)}else i=A[h];q(i,b),q(w,b)}function m(c){c.writeByte(x),remaining=a*b,curPixel=0,l(x+1,c),c.writeByte(0)}function n(a){s>0&&(a.writeByte(s),a.writeBytes(y,0,s),s=0)}function o(a){return(1<0?r|=a<=8;)i(255&r,b),r>>=8,B-=8;if((C>t||D)&&(D?(t=o(n_bits=u),D=!1):(++n_bits,t=n_bits==d?1<0;)i(255&r,b),r>>=8,B-=8;n(b)}}var r,s,t,u,v,w,x=Math.max(2,h),y=new Uint8Array(256),z=new Int32Array(e),A=new Int32Array(e),B=0,C=0,D=!1;this.encode=m}var c=-1,d=12,e=5003,f=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];a.exports=b}),a.define("/SimpleQuant.js",function(a){function b(a,b,c){return[a,b,c].join(".")}function c(a){this.pixels=a,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){for(var a=this.pixels.length/3,c=0,d=0;a>d;d++){var e=this.pixels[c++],f=this.pixels[c++],g=this.pixels[c++],h=b(e,f,g);this.paletteIndex[h]||(this.palette.push(e),this.palette.push(f),this.palette.push(g),this.paletteIndex[h]=this.palette.length/3-1)}},this.lookupRGB=function(a,c,d){return this.paletteIndex[b(a,c,d)]}}a.exports=c}),a.define("/TypedNeuQuant.js",function(a){function b(a,b){function m(){H=[],I=new Int32Array(256),J=new Int32Array(d),K=new Int32Array(d),L=new Int32Array(d>>3);var a,b;for(a=0;d>a;a++)b=(a<a;a++)H[a][0]>>=f,H[a][1]>>=f,H[a][2]>>=f,H[a][3]=a}function r(a,b,c,d,e){H[b][0]-=a*(H[b][0]-c)/s,H[b][1]-=a*(H[b][1]-d)/s,H[b][2]-=a*(H[b][2]-e)/s}function t(a,b,c,e,f){for(var g,h,i=Math.abs(b-a),j=Math.min(b+a,d),k=b+1,l=b-1,m=1;j>k||l>i;)h=L[m++],j>k&&(g=H[k++],g[0]-=h*(g[0]-c)/w,g[1]-=h*(g[1]-e)/w,g[2]-=h*(g[2]-f)/w),l>i&&(g=H[l--],g[0]-=h*(g[0]-c)/w,g[1]-=h*(g[1]-e)/w,g[2]-=h*(g[2]-f)/w)}function v(a,b,c){var e,h,m,n,o,p=2147483647,q=p,r=-1,s=r;for(e=0;d>e;e++)h=H[e],m=Math.abs(h[0]-a)+Math.abs(h[1]-b)+Math.abs(h[2]-c),p>m&&(p=m,r=e),n=m-(J[e]>>g-f),q>n&&(q=n,s=e),o=K[e]>>j,K[e]-=o,J[e]+=o<a;a++){for(c=H[a],g=a,h=c[1],b=a+1;d>b;b++)f=H[b],f[1]>1,b=i+1;h>b;b++)I[b]=a;i=h,j=a}}for(I[i]=j+e>>1,b=i+1;256>b;b++)I[b]=e}function D(a,b,c){for(var e,f,g,h=1e3,i=-1,j=I[b],k=j-1;d>j||k>=0;)d>j&&(f=H[j],g=f[1]-b,g>=h?j=d:(j++,0>g&&(g=-g),e=f[0]-a,0>e&&(e=-e),g+=e,h>g&&(e=f[2]-c,0>e&&(e=-e),g+=e,h>g&&(h=g,i=f[3])))),k>=0&&(f=H[k],g=b-f[1],g>=h?k=-1:(k--,0>g&&(g=-g),e=f[0]-a,0>e&&(e=-e),g+=e,h>g&&(e=f[2]-c,0>e&&(e=-e),g+=e,h>g&&(h=g,i=f[3]))));return i}function E(){var d,e=a.length,g=30+(b-1)/3,h=e/(3*b),i=~~(h/c),j=s,k=p,l=k>>n;for(1>=l&&(l=0),d=0;l>d;d++)L[d]=j*((l*l-d*d)*u/(l*l));var m;B>e?(b=1,m=3):m=e%x!==0?3*x:e%y!==0?3*y:e%z!==0?3*z:3*A;var o,w,C,D,E=0;for(d=0;h>d;)if(o=(255&a[E])<=e&&(E-=e),d++,0===i&&(i=1),d%i===0)for(j-=j/g,k-=k/q,l=k>>n,1>=l&&(l=0),D=0;l>D;D++)L[D]=j*((l*l-D*D)*u/(l*l))}function F(){m(),E(),o(),C()}function G(){for(var a=[],b=[],c=0;d>c;c++)b[H[c][3]]=c;for(var e=0,f=0;d>f;f++){var g=b[f];a[e++]=H[g][0],a[e++]=H[g][1],a[e++]=H[g][2]}return a}var H,I,J,K,L;this.buildColormap=F,this.getColormap=G,this.lookupRGB=D}var c=100,d=256,e=d-1,f=4,g=16,h=1<>j,l=h<>3,n=6,o=1<c;++c)if(c in b&&b[c]===a)return!0;return!1}function e(a,b){function d(){this.constructor=a}for(var e in b)c(b,e)&&(a[e]=b[e]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a}var f,g,h,i,j;h=b("events",a).EventEmitter,f=b("/browser.coffee",a),j=function(a){function b(a){var b,c;this.running=!1,this.options={},this.frames=[],this.freeWorkers=[],this.activeWorkers=[],this.setOptions(a);for(b in g)c=g[b],null!=this.options[b]?this.options[b]:this.options[b]=c}return e(b,a),g={workerScript:window.GifWorkerURL,workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null,preserveColors:!1},i={delay:500,copy:!1},b.prototype.setOption=function(a,b){return this.options[a]=b,null==this._canvas||"width"!==a&&"height"!==a?void 0:this._canvas[a]=b},b.prototype.setOptions=function(a){var b,d;return function(e){for(b in a)c(a,b)&&(d=a[b],e.push(this.setOption(b,d)));return e}.call(this,[])},b.prototype.addFrame=function(a,b){var c,d;null==b&&(b={}),c={},c.transparent=this.options.transparent;for(d in i)c[d]=b[d]||i[d];if(null!=this.options.width||this.setOption("width",a.width),null!=this.options.height||this.setOption("height",a.height),"undefined"!=typeof ImageData&&null!=ImageData&&a instanceof ImageData)c.data=a.data;else if("undefined"!=typeof CanvasRenderingContext2D&&null!=CanvasRenderingContext2D&&a instanceof CanvasRenderingContext2D||"undefined"!=typeof WebGLRenderingContext&&null!=WebGLRenderingContext&&a instanceof WebGLRenderingContext)b.copy?c.data=this.getContextData(a):c.context=a;else{if(null==a.childNodes)throw new Error("Invalid image");b.copy?c.data=this.getImageData(a):c.image=a}return this.frames.push(c)},b.prototype.render=function(){var a,b;if(this.running)throw new Error("Already running");if(null==this.options.width||null==this.options.height)throw new Error("Width and height must be set prior to rendering");this.running=!0,this.nextFrame=0,this.finishedFrames=0,this.imageParts=function(b){for(var c=function(){var a;a=[];for(var b=0;0<=this.frames.length?bthis.frames.length;0<=this.frames.length?++b:--b)a.push(b);return a}.apply(this,arguments),d=0,e=c.length;e>d;++d)a=c[d],b.push(null);return b}.call(this,[]),b=this.spawnWorkers();for(var c=function(){var a;a=[];for(var c=0;b>=0?b>c:c>b;b>=0?++c:--c)a.push(c);return a}.apply(this,arguments),d=0,e=c.length;e>d;++d)a=c[d],this.renderNextFrame();return this.emit("start"),this.emit("progress",0)},b.prototype.abort=function(){for(var a;;){if(a=this.activeWorkers.shift(),!(null!=a))break;console.log("killing active worker"),a.terminate()}return this.running=!1,this.emit("abort")},b.prototype.spawnWorkers=function(){var a;return a=Math.min(this.options.workers,this.frames.length),function(){var b;b=[];for(var c=this.freeWorkers.length;this.freeWorkers.length<=a?a>c:c>a;this.freeWorkers.length<=a?++c:--c)b.push(c);return b}.apply(this,arguments).forEach(function(a){return function(b){var c;return console.log("spawning worker "+b),c=new Worker(a.options.workerScript),c.onmessage=function(a){return function(b){return a.activeWorkers.splice(a.activeWorkers.indexOf(c),1),a.freeWorkers.push(c),a.frameFinished(b.data)}}(a),a.freeWorkers.push(c)}}(this)),a},b.prototype.frameFinished=function(a){return console.log("frame "+a.index+" finished - "+this.activeWorkers.length+" active"),this.finishedFrames++,this.emit("progress",this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,d(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},b.prototype.finishRendering=function(){var a,b,c,d,e,f,g;e=0;for(var h=0,i=this.imageParts.length;i>h;++h)b=this.imageParts[h],e+=(b.data.length-1)*b.pageSize+b.cursor;e+=b.pageSize-b.cursor,console.log("rendering finished - filesize "+Math.round(e/1e3)+"kb"),a=new Uint8Array(e),f=0;for(var j=0,k=this.imageParts.length;k>j;++j){b=this.imageParts[j];for(var l=0,m=b.data.length;m>l;++l)g=b.data[l],c=l,a.set(g,f),f+=c===b.data.length-1?b.cursor:b.pageSize}return d=new Blob([a],{type:"image/gif"}),this.emit("finished",d,a)},b.prototype.renderNextFrame=function(){var a,b,c;if(0===this.freeWorkers.length)throw new Error("No free workers");return this.nextFrame>=this.frames.length?void 0:(a=this.frames[this.nextFrame++],c=this.freeWorkers.shift(),b=this.getTask(a),console.log("starting frame "+(b.index+1)+" of "+this.frames.length),this.activeWorkers.push(c),c.postMessage(b))},b.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},b.prototype.getImageData=function(a){var b;return null!=this._canvas||(this._canvas=document.createElement("canvas"),this._canvas.width=this.options.width,this._canvas.height=this.options.height),b=this._canvas.getContext("2d"),b.setFill=this.options.background,b.fillRect(0,0,this.options.width,this.options.height),b.drawImage(a,0,0),this.getContextData(b)},b.prototype.getTask=function(a){var b,c;if(b=this.frames.indexOf(a),c={index:b,last:b===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:"chrome"===f.name},null!=a.data)c.data=a.data;else if(null!=a.context)c.data=this.getContextData(a.context);else{if(null==a.image)throw new Error("Invalid frame");c.data=this.getImageData(a.image)}return c},b}(h),a.exports=j}),b.define("/browser.coffee",function(a){var b,c,d,e,f;e=navigator.userAgent.toLowerCase(),d=navigator.platform.toLowerCase(),f=e.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0],c="ie"===f[1]&&document.documentMode,b={name:"version"===f[1]?f[3]:f[1],version:c||parseFloat("opera"===f[1]&&f[4]?f[4]:f[2]),platform:{name:e.match(/ip(?:ad|od|hone)/)?"ios":(e.match(/(?:webos|android)/)||d.match(/mac|win|linux/)||["other"])[0]}},b[b.name]=!0,b[b.name+parseInt(b.version,10)]=!0,b.platform[b.platform.name]=!0,a.exports=b}),b.define("events",function(a,b){c.EventEmitter||(c.EventEmitter=function(){});var d=b.EventEmitter=c.EventEmitter,e="function"==typeof Array.isArray?Array.isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},f=10;d.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},d.prototype.emit=function(a){if("error"===a&&(!this._events||!this._events.error||e(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var b=this._events[a];if(!b)return!1;if("function"!=typeof b){if(e(b)){for(var c=Array.prototype.slice.call(arguments,1),d=b.slice(),f=0,g=d.length;g>f;f++)d[f].apply(this,c);return!0}return!1}switch(arguments.length){case 1:b.call(this);break;case 2:b.call(this,arguments[1]);break;case 3:b.call(this,arguments[1],arguments[2]);break;default:var c=Array.prototype.slice.call(arguments,1);b.apply(this,c)}return!0},d.prototype.addListener=function(a,b){if("function"!=typeof b)throw new Error("addListener only takes instances of Function");if(this._events||(this._events={}),this.emit("newListener",a,b),this._events[a])if(e(this._events[a])){if(!this._events[a].warned){var c;c=void 0!==this._events.maxListeners?this._events.maxListeners:f,c&&c>0&&this._events[a].length>c&&(this._events[a].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];else this._events[a]=b;return this},d.prototype.on=d.prototype.addListener,d.prototype.once=function(a,b){var c=this;return c.on(a,function d(){c.removeListener(a,d),b.apply(this,arguments)}),this},d.prototype.removeListener=function(a,b){if("function"!=typeof b)throw new Error("removeListener only takes instances of Function");if(!this._events||!this._events[a])return this;var c=this._events[a];if(e(c)){var d=c.indexOf(b);if(0>d)return this;c.splice(d,1),0==c.length&&delete this._events[a]}else this._events[a]===b&&delete this._events[a];return this},d.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},d.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),e(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),a.GIF=b("/gif.coffee")}.call(this,this),function(a){"use strict";var b=function(a){this.data=a,this.len=this.data.length,this.pos=0};b.prototype.readByte=function(){if(this.pos>=this.data.length)throw new Error("Attempted to read past end of stream.");return 255&this.data.charCodeAt(this.pos++)},b.prototype.readBytes=function(a){for(var b=[],c=0;a>c;c++)b.push(this.readByte());return b},b.prototype.read=function(a){for(var b="",c=0;a>c;c++)b+=String.fromCharCode(this.readByte());return b},b.prototype.readUnsigned=function(){var a=this.readBytes(2);return(a[1]<<8)+a[0]};var c=a.SuperGIF=a.SuperGIF||{};c.Stream=b}(window),function(a){"use strict";var b=function(a){return a.reduce(function(a,b){return 2*a+b},0)},c=function(a){for(var b=[],c=7;c>=0;c--)b.push(!!(a&1<=this.data.length)throw new Error("Attempted to read past end of stream.");return 255&a.charCodeAt(this.pos++)},this.readBytes=function(a){for(var b=[],c=0;a>c;c++)b.push(this.readByte());return b},this.read=function(a){for(var b="",c=0;a>c;c++)b+=String.fromCharCode(this.readByte());return b},this.readUnsigned=function(){var a=this.readBytes(2);return(a[1]<<8)+a[0]}},e=function(a,b){for(var c,d,e=0,f=function(a){for(var c=0,d=0;a>d;d++)b.charCodeAt(e>>3)&1<<(7&e)&&(c|=1<b;b++)k[b]=[b];k[h]=[],k[i]=null};;)if(d=c,c=f(j),c!==h){if(c===i)break;if(cj&&j++}else l();return g},f=function(a,d){d||(d={});var f=function(b){for(var c=[],d=0;b>d;d++)c.push(a.readBytes(3));return c},g=function(){var b,c;c="";do b=a.readByte(),c+=a.read(b);while(0!==b);return c},h=function(){var e={};if(e.sig=a.read(3),e.ver=a.read(3),"GIF"!==e.sig)throw d.onError(),new Error("Not a GIF file.");e.width=a.readUnsigned(),e.height=a.readUnsigned();var g=c(a.readByte());e.gctFlag=g.shift(),e.colorRes=b(g.splice(0,3)),e.sorted=g.shift(),e.gctSize=b(g.splice(0,3)),e.bgColor=a.readByte(),e.pixelAspectRatio=a.readByte(),e.gctFlag&&(e.gct=f(1<i;i++)for(var j=f[i];d>j;j+=g[i])e(j,h),h++;return c};h.leftPos=a.readUnsigned(),h.topPos=a.readUnsigned(),h.width=a.readUnsigned(),h.height=a.readUnsigned();var j=c(a.readByte());h.lctFlag=j.shift(),h.interlaced=j.shift(),h.sorted=j.shift(),h.reserved=j.splice(0,2),h.lctSize=b(j.splice(0,3)),h.lctFlag&&(h.lct=f(1<0&&(3===o?p.putImageData(r[n].data,0,0):n=b-1,2===o&&p.clearRect(q.leftPos,q.topPos,q.width,q.height));var d=p.getImageData(a.leftPos,a.topPos,a.width,a.height),e=d.data;a.pixels.forEach(function(a,b){a!==k&&(e[4*b+0]=c[a][0],e[4*b+1]=c[a][1],e[4*b+2]=c[a][2],e[4*b+3]=255)}),p.putImageData(d,a.leftPos,a.topPos),q=a},B={hdr:x,gce:y,img:A,eof:function(){z(),j=!1,C&&C()},onError:function(){D&&D()}},C=!1,D=!1,E=document.createElement("canvas");return{load:function(b){if(C=b.success,D=b.error,j=!0,-1!==s.src.indexOf("data:")){var c=s.src.substring(s.src.indexOf(",")+1);g=new d(a.atob(c)),u()}else{var e=new XMLHttpRequest;e.overrideMimeType("text/plain; charset=x-user-defined"),e.onload=function(){g=new d(e.responseText),setTimeout(u,0)},e.onerror=function(){w("xhr")},e.open("GET",s.getAttribute("data-animated-src")||s.src,!0),e.send()}},getFrames:function(){return r}}};a.SuperGif=g}(window),!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A -},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;d=2*e+2,!(d>=this.length)&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)}),function(a,b,c){function d(a,b,c){for(var d=[],e=0;e')}return"
        "+d.join("")+"
        "}function e(){for(var a=0;a1&&(delete a.localStorage[W],b.each(e,function(a,b){t(b)}))}catch(f){}try{nb=a.localStorage[W].split(";")}catch(f){}}Kb.bind("click.spectrum touchstart.spectrum",function(a){tb||B(),a.stopPropagation(),b(a.target).is("input")||a.preventDefault()}),(sb.is(":disabled")||T.disabled===!0)&&S(),ub.click(j),Cb.change(A),Cb.bind("paste",function(){setTimeout(A,1)}),Cb.keydown(function(a){13==a.keyCode&&A()}),Fb.text(T.cancelText),Fb.bind("click.spectrum",function(a){a.stopPropagation(),a.preventDefault(),F("cancel")}),Gb.text(T.chooseText),Gb.bind("click.spectrum",function(a){a.stopPropagation(),a.preventDefault(),J()&&(N(!0),F())}),l(Ab,function(a,b,c){kb=a/eb,c.shiftKey&&(kb=Math.round(10*kb)/10),K() -}),l(xb,function(a,b){hb=parseFloat(b/cb),K()},y,z),l(vb,function(a,b,c){if(c.shiftKey){if(!qb){var d=ib*_,e=ab-jb*ab,f=Math.abs(a-d)>Math.abs(b-e);qb=f?"x":"y"}}else qb=null;var g=!qb||"x"===qb,h=!qb||"y"===qb;g&&(ib=parseFloat(a/_)),h&&(jb=parseFloat((ab-b)/ab)),K()},y,z),Mb?(H(Mb),L(),Pb=Ob||u(Mb).format,t(Mb)):L(),U&&C();var g=p?"mousedown.spectrum":"click.spectrum touchstart.spectrum";Db.delegate(".sp-thumb-el",g,c),Eb.delegate(".sp-thumb-el:nth-child(1)",g,{ignore:!0},c)}function t(c){if(V){var d=u(c).toRgbString();if(-1===b.inArray(d,nb))for(nb.push(d);nb.length>ob;)nb.shift();if(W&&a.localStorage)try{a.localStorage[W]=nb.join(";")}catch(e){}}}function v(){var a,b=[],c=nb,d={};if(T.showPalette){for(var e=0;e=ab||0>=_||0>=cb)&&O(),ub.addClass(pb),qb=null}function z(){ub.removeClass(pb)}function A(){var a=u(Cb.val());a.ok?H(a):Cb.addClass("sp-validation-error")}function B(){$?F():C()}function C(){var c=b.Event("beforeShow.spectrum");return $?void O():(Nb=I(),sb.trigger(c,[Nb]),void(Y.beforeShow(Nb)===!1||c.isDefaultPrevented()||(H(Nb),e(),$=!0,b(rb).bind("mousedown.spectrum",D),b(rb).bind("mouseup.spectrum",E),b(a).bind("resize.spectrum",Z),Jb.addClass("sp-active"),ub.removeClass("sp-hidden"),T.showPalette&&w(),O(),L(),x(),Y.show(Nb),sb.trigger("show.spectrum",[Nb]))))}function D(a){var c=b(a.target),d=c.parents(),e=!d.is(ub)&&!c.is(ub);e&&F(a)}function E(a){var b=!u.equals(I(),Nb);b&&(Qb&&"cancel"!==a?N(!0):G())}function F(c){c&&"click"==c.type&&2==c.button||$&&!U&&($=!1,b(rb).unbind("mousedown.spectrum",D),b(rb).unbind("mouseup.spectrum",E),b(a).unbind("resize.spectrum",Z),Jb.removeClass("sp-active"),ub.addClass("sp-hidden"),E(c),t(I()),Y.hide(I()),sb.trigger("hide.spectrum",[I()]))}function G(){H(Nb,!0)}function H(a,b){if(!u.equals(a,I())){var c=u(a),d=c.toHsv();hb=d.h%360/360,ib=d.s,jb=d.v,kb=d.a,L(),c.ok&&!b&&(Pb=Ob||c.format)}}function I(a){return a=a||{},u.fromRatio({h:hb,s:ib,v:jb,a:Math.round(100*kb)/100},{format:a.format||Pb})}function J(){return!Cb.hasClass("sp-validation-error")}function K(){L(),Y.move(I()),sb.trigger("move.spectrum",[I()])}function L(){Cb.removeClass("sp-validation-error"),M();var a=u.fromRatio({h:hb,s:1,v:1});vb.css("background-color",a.toHexString());var b=Pb;1>kb&&("hex"===b||"hex3"===b||"hex6"===b||"name"===b)&&(b="rgb");var c=I({format:b}),d=c.toHexString(),e=c.toRgbString();if(q||1===c.alpha?Lb.css("background-color",e):(Lb.css("background-color","transparent"),Lb.css("filter",c.toFilter())),T.showAlpha){var f=c.toRgb();f.a=0;var g=u(f).toRgbString(),h="linear-gradient(left, "+g+", "+d+")";p?zb.css("filter",u(g).toFilter({gradientType:1},d)):(zb.css("background","-webkit-"+h),zb.css("background","-moz-"+h),zb.css("background","-ms-"+h),zb.css("background",h))}T.showInput&&Cb.val(c.toString(Constants.PREFERRED_COLOR_FORMAT||b)),T.showPalette&&w(),x()}function M(){var a=ib,b=jb,c=a*_,d=ab-b*ab;c=Math.max(-bb/2,Math.min(_-bb/2,c-bb/2)),d=Math.max(-bb/2,Math.min(ab-bb/2,d-bb/2)),wb.css({top:d,left:c});var e=kb*eb;Bb.css({left:e-fb/2});var f=hb*cb;yb.css({top:f-gb/2})}function N(a){var b=I();Hb&&sb.val(b.toString(Pb));var c=!u.equals(b,Nb);Nb=b,a&&c&&(Y.change(b),sb.trigger("change",[b]))}function O(){_=vb.width(),ab=vb.height(),bb=wb.height()+4,db=xb.width(),cb=xb.height(),gb=yb.height()+4,eb=Ab.width(),fb=Bb.width(),U||(ub.css("position","absolute"),ub.offset(h(ub,Kb))),M()}function P(){sb.show(),Kb.unbind("click.spectrum touchstart.spectrum"),ub.remove(),Jb.remove(),o[Rb.id]=null}function Q(a,d){return a===c?b.extend({},T):d===c?T[a]:(T[a]=d,void k())}function R(){tb=!1,sb.attr("disabled",!1),Kb.removeClass("sp-disabled")}function S(){F(),tb=!0,sb.attr("disabled",!0),Kb.addClass("sp-disabled")}var T=f(i,g),U=T.flat,V=T.showSelectionPalette,W=T.localStorageKey,X=T.theme,Y=T.callbacks,Z=m(O,10),$=!1,_=0,ab=0,bb=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0,jb=0,kb=1,lb=T.palette.slice(0),mb=b.isArray(lb[0])?lb:[lb],nb=T.selectionPalette.slice(0),ob=T.maxSelectionSize,pb="sp-dragging",qb=null,rb=g.ownerDocument,sb=(rb.body,b(g)),tb=!1,ub=b(s,rb).addClass(X),vb=ub.find(".sp-color"),wb=ub.find(".sp-dragger"),xb=ub.find(".sp-hue"),yb=ub.find(".sp-slider"),zb=ub.find(".sp-alpha-inner"),Ab=ub.find(".sp-alpha"),Bb=ub.find(".sp-alpha-handle"),Cb=ub.find(".sp-input"),Db=ub.find(".sp-palette"),Eb=ub.find(".sp-initial"),Fb=ub.find(".sp-cancel"),Gb=ub.find(".sp-choose"),Hb=sb.is("input"),Ib=Hb&&!U,Jb=Ib?b(r).addClass(X).addClass(T.className):b([]),Kb=Ib?Jb:sb,Lb=Jb.find(".sp-preview-inner"),Mb=T.color||Hb&&sb.val(),Nb=!1,Ob=T.preferredFormat,Pb=Ob,Qb=!T.showButtons||T.clickoutFiresChange;n();var Rb={show:C,hide:F,toggle:B,reflow:O,option:Q,enable:R,disable:S,set:function(a){H(a),N()},get:I,destroy:P,container:ub};return Rb.id=o.push(Rb)-1,Rb}function h(a,c){var d=0,e=a.outerWidth(),f=a.outerHeight(),g=c.outerHeight(),h=a[0].ownerDocument,i=h.documentElement,j=i.clientWidth+b(h).scrollLeft(),k=i.clientHeight+b(h).scrollTop(),l=c.offset();return l.top+=g,Math.min(l.left,l.left+e>j&&j>e)?(l.left-=Math.abs(l.left+e-j),a.attr("data-x-position","right")):(l.left-=0,a.attr("data-x-position","left")),Math.min(l.top,l.top+f>k&&k>f)?(l.top-=Math.abs(f+g-d),a.attr("data-y-position","top")):(l.top-=d,a.attr("data-y-position","bottom")),l}function i(){}function j(a){a.stopPropagation()}function k(a,b){var c=Array.prototype.slice,d=c.call(arguments,2);return function(){return a.apply(b,d.concat(c.call(arguments)))}}function l(c,d,e,f){function g(a){a.stopPropagation&&a.stopPropagation(),a.preventDefault&&a.preventDefault(),a.returnValue=!1}function h(a){if(l){if(p&&document.documentMode<9&&!a.button)return j();var b=a.originalEvent.touches,e=b?b[0].pageX:a.pageX,f=b?b[0].pageY:a.pageY,h=Math.max(0,Math.min(e-m.left,o)),i=Math.max(0,Math.min(f-m.top,n));q&&g(a),d.apply(c,[h,i,a])}}function i(a){{var d=a.which?3==a.which:2==a.button;a.originalEvent.touches}d||l||e.apply(c,arguments)!==!1&&(l=!0,n=b(c).height(),o=b(c).width(),m=b(c).offset(),b(k).bind(r),b(k.body).addClass("sp-dragging"),q||h(a),g(a))}function j(){l&&(b(k).unbind(r),b(k.body).removeClass("sp-dragging"),f.apply(c,arguments)),l=!1}d=d||function(){},e=e||function(){},f=f||function(){};var k=c.ownerDocument||document,l=!1,m={},n=0,o=0,q="ontouchstart"in a,r={};r.selectstart=g,r.dragstart=g,r["touchmove mousemove"]=h,r["touchend mouseup"]=j,b(c).bind("touchstart mousedown",i)}function m(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,a.apply(e,f)};c&&clearTimeout(d),(c||!d)&&(d=setTimeout(g,b))}}var n={beforeShow:i,move:i,change:i,show:i,hide:i,color:!1,flat:!1,showInput:!1,showButtons:!0,clickoutFiresChange:!1,showInitial:!1,showPalette:!1,showPaletteOnly:!1,showSelectionPalette:!0,localStorageKey:!1,appendTo:"body",maxSelectionSize:7,cancelText:"cancel",chooseText:"choose",preferredFormat:!1,className:"",showAlpha:!1,theme:"sp-light",palette:["fff","000"],selectionPalette:[],disabled:!1},o=[],p=!!/msie/i.exec(a.navigator.userAgent),q=function(){function a(a,b){return!!~(""+a).indexOf(b)}var b=document.createElement("div"),c=b.style;return c.cssText="background-color:rgba(0,0,0,.5)",a(c.backgroundColor,"rgba")||a(c.backgroundColor,"hsla")}(),r=["
        ","
        ","
        ","
        "].join(""),s=function(){var a="";if(p)for(var b=1;6>=b;b++)a+="
        ";return["
        "].join("")}(),t="spectrum.id";b.fn.spectrum=function(a){if("string"==typeof a){var c=this,d=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=o[b(this).data(t)];if(e){var f=e[a];if(!f)throw new Error("Spectrum: no such method: '"+a+"'");"get"==a?c=e.get():"container"==a?c=e.container:"option"==a?c=e.option.apply(e,d):"destroy"==a?(e.destroy(),b(this).removeData(t)):f.apply(e,d)}}),c}return this.spectrum("destroy").each(function(){var c=g(this,a);b(this).data(t,c.id)})},b.fn.spectrum.load=!0,b.fn.spectrum.loadOpts={},b.fn.spectrum.draggable=l,b.fn.spectrum.defaults=n,b.spectrum={},b.spectrum.localization={},b.spectrum.palettes={},b.fn.spectrum.processNativeColorInputs=function(){var a=b("")[0],c="color"===a.type&&"!"!=a.value;c||b("input[type=color]").spectrum({preferredFormat:"hex6"})},function(){function b(a,d){if(a=a?a:"",d=d||{},"object"==typeof a&&a.hasOwnProperty("_tc_id"))return a;var f=c(a),h=f.r,j=f.g,m=f.b,n=f.a,o=x(100*n)/100,p=d.format||f.format;return 1>h&&(h=x(h)),1>j&&(j=x(j)),1>m&&(m=x(m)),{ok:f.ok,format:p,_tc_id:v++,alpha:n,getAlpha:function(){return n},setAlpha:function(a){n=k(a),o=x(100*n)/100},toHsv:function(){var a=g(h,j,m);return{h:360*a.h,s:a.s,v:a.v,a:n}},toHsvString:function(){var a=g(h,j,m),b=x(360*a.h),c=x(100*a.s),d=x(100*a.v);return 1==n?"hsv("+b+", "+c+"%, "+d+"%)":"hsva("+b+", "+c+"%, "+d+"%, "+o+")"},toHsl:function(){var a=e(h,j,m);return{h:360*a.h,s:a.s,l:a.l,a:n}},toHslString:function(){var a=e(h,j,m),b=x(360*a.h),c=x(100*a.s),d=x(100*a.l);return 1==n?"hsl("+b+", "+c+"%, "+d+"%)":"hsla("+b+", "+c+"%, "+d+"%, "+o+")"},toHex:function(a){return i(h,j,m,a)},toHexString:function(a){return"#"+i(h,j,m,a)},toRgb:function(){return{r:x(h),g:x(j),b:x(m),a:n}},toRgbString:function(){return 1==n?"rgb("+x(h)+", "+x(j)+", "+x(m)+")":"rgba("+x(h)+", "+x(j)+", "+x(m)+", "+o+")"},toPercentageRgb:function(){return{r:x(100*l(h,255))+"%",g:x(100*l(j,255))+"%",b:x(100*l(m,255))+"%",a:n}},toPercentageRgbString:function(){return 1==n?"rgb("+x(100*l(h,255))+"%, "+x(100*l(j,255))+"%, "+x(100*l(m,255))+"%)":"rgba("+x(100*l(h,255))+"%, "+x(100*l(j,255))+"%, "+x(100*l(m,255))+"%, "+o+")"},toName:function(){return 0===n?"transparent":C[i(h,j,m,!0)]||!1},toFilter:function(a){var c=i(h,j,m),e=c,f=Math.round(255*parseFloat(n)).toString(16),g=f,k=d&&d.gradientType?"GradientType = 1, ":"";if(a){var l=b(a);e=l.toHex(),g=Math.round(255*parseFloat(l.alpha)).toString(16)}return"progid:DXImageTransform.Microsoft.gradient("+k+"startColorstr=#"+q(f)+c+",endColorstr=#"+q(g)+e+")"},toString:function(a){var b=!!a;a=a||this.format;var c=!1,d=!b&&1>n&&n>0,e=d&&("hex"===a||"hex6"===a||"hex3"===a||"name"===a);return"rgb"===a&&(c=this.toRgbString()),"prgb"===a&&(c=this.toPercentageRgbString()),("hex"===a||"hex6"===a)&&(c=this.toHexString()),"hex3"===a&&(c=this.toHexString(!0)),"name"===a&&(c=this.toName()),"hsl"===a&&(c=this.toHslString()),"hsv"===a&&(c=this.toHsvString()),e?this.toRgbString():c||this.toHexString()}}}function c(a){var b={r:0,g:0,b:0},c=1,e=!1,g=!1;return"string"==typeof a&&(a=s(a)),"object"==typeof a&&(a.hasOwnProperty("r")&&a.hasOwnProperty("g")&&a.hasOwnProperty("b")?(b=d(a.r,a.g,a.b),e=!0,g="%"===String(a.r).substr(-1)?"prgb":"rgb"):a.hasOwnProperty("h")&&a.hasOwnProperty("s")&&a.hasOwnProperty("v")?(a.s=r(a.s),a.v=r(a.v),b=h(a.h,a.s,a.v),e=!0,g="hsv"):a.hasOwnProperty("h")&&a.hasOwnProperty("s")&&a.hasOwnProperty("l")&&(a.s=r(a.s),a.l=r(a.l),b=f(a.h,a.s,a.l),e=!0,g="hsl"),a.hasOwnProperty("a")&&(c=a.a)),c=k(c),{ok:e,format:a.format||g,r:y(255,z(b.r,0)),g:y(255,z(b.g,0)),b:y(255,z(b.b,0)),a:c}}function d(a,b,c){return{r:255*l(a,255),g:255*l(b,255),b:255*l(c,255)}}function e(a,b,c){a=l(a,255),b=l(b,255),c=l(c,255);var d,e,f=z(a,b,c),g=y(a,b,c),h=(f+g)/2;if(f==g)d=e=0;else{var i=f-g;switch(e=h>.5?i/(2-f-g):i/(f+g),f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return{h:d,s:e,l:h}}function f(a,b,c){function d(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+(b-a)*(2/3-c)*6:a}var e,f,g;if(a=l(a,360),b=l(b,100),c=l(c,100),0===b)e=f=g=c;else{var h=.5>c?c*(1+b):c+b-c*b,i=2*c-h;e=d(i,h,a+1/3),f=d(i,h,a),g=d(i,h,a-1/3)}return{r:255*e,g:255*f,b:255*g}}function g(a,b,c){a=l(a,255),b=l(b,255),c=l(c,255);var d,e,f=z(a,b,c),g=y(a,b,c),h=f,i=f-g;if(e=0===f?0:i/f,f==g)d=0;else{switch(f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return{h:d,s:e,v:h}}function h(a,b,c){a=6*l(a,360),b=l(b,100),c=l(c,100);var d=w.floor(a),e=a-d,f=c*(1-b),g=c*(1-e*b),h=c*(1-(1-e)*b),i=d%6,j=[c,g,f,f,h,c][i],k=[h,c,c,g,f,f][i],m=[f,f,h,c,c,g][i];return{r:255*j,g:255*k,b:255*m}}function i(a,b,c,d){var e=[q(x(a).toString(16)),q(x(b).toString(16)),q(x(c).toString(16))];return d&&e[0].charAt(0)==e[0].charAt(1)&&e[1].charAt(0)==e[1].charAt(1)&&e[2].charAt(0)==e[2].charAt(1)?e[0].charAt(0)+e[1].charAt(0)+e[2].charAt(0):e.join("")}function j(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[a[c]]=c);return b}function k(a){return a=parseFloat(a),(isNaN(a)||0>a||a>1)&&(a=1),a}function l(a,b){o(a)&&(a="100%");var c=p(a);return a=y(b,z(0,parseFloat(a))),c&&(a=parseInt(a*b,10)/100),w.abs(a-b)<1e-6?1:a%b/parseFloat(b)}function m(a){return y(1,z(0,a))}function n(a){return parseInt(a,16)}function o(a){return"string"==typeof a&&-1!=a.indexOf(".")&&1===parseFloat(a)}function p(a){return"string"==typeof a&&-1!=a.indexOf("%")}function q(a){return 1==a.length?"0"+a:""+a}function r(a){return 1>=a&&(a=100*a+"%"),a}function s(a){a=a.replace(t,"").replace(u,"").toLowerCase();var b=!1;if(B[a])a=B[a],b=!0;else if("transparent"==a)return{r:0,g:0,b:0,a:0,format:"name"};var c;return(c=D.rgb.exec(a))?{r:c[1],g:c[2],b:c[3]}:(c=D.rgba.exec(a))?{r:c[1],g:c[2],b:c[3],a:c[4]}:(c=D.hsl.exec(a))?{h:c[1],s:c[2],l:c[3]}:(c=D.hsla.exec(a))?{h:c[1],s:c[2],l:c[3],a:c[4]}:(c=D.hsv.exec(a))?{h:c[1],s:c[2],v:c[3]}:(c=D.hex6.exec(a))?{r:n(c[1]),g:n(c[2]),b:n(c[3]),format:b?"name":"hex"}:(c=D.hex3.exec(a))?{r:n(c[1]+""+c[1]),g:n(c[2]+""+c[2]),b:n(c[3]+""+c[3]),format:b?"name":"hex"}:!1}var t=/^[\s,#]+/,u=/\s+$/,v=0,w=Math,x=w.round,y=w.min,z=w.max,A=w.random;b.fromRatio=function(a,c){if("object"==typeof a){var d={};for(var e in a)a.hasOwnProperty(e)&&(d[e]="a"===e?a[e]:r(a[e]));a=d}return b(a,c)},b.equals=function(a,c){return a&&c?b(a).toRgbString()==b(c).toRgbString():!1},b.random=function(){return b.fromRatio({r:A(),g:A(),b:A()})},b.desaturate=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.s-=c/100,d.s=m(d.s),b(d)},b.saturate=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.s+=c/100,d.s=m(d.s),b(d)},b.greyscale=function(a){return b.desaturate(a,100)},b.lighten=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.l+=c/100,d.l=m(d.l),b(d)},b.darken=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.l-=c/100,d.l=m(d.l),b(d)},b.complement=function(a){var c=b(a).toHsl();return c.h=(c.h+180)%360,b(c)},b.triad=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+120)%360,s:c.s,l:c.l}),b({h:(d+240)%360,s:c.s,l:c.l})]},b.tetrad=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+90)%360,s:c.s,l:c.l}),b({h:(d+180)%360,s:c.s,l:c.l}),b({h:(d+270)%360,s:c.s,l:c.l})]},b.splitcomplement=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+72)%360,s:c.s,l:c.l}),b({h:(d+216)%360,s:c.s,l:c.l})]},b.analogous=function(a,c,d){c=c||6,d=d||30;var e=b(a).toHsl(),f=360/d,g=[b(a)];for(e.h=(e.h-(f*c>>1)+720)%360;--c;)e.h=(e.h+f)%360,g.push(b(e));return g},b.monochromatic=function(a,c){c=c||6;for(var d=b(a).toHsv(),e=d.h,f=d.s,g=d.v,h=[],i=1/c;c--;)h.push(b({h:e,s:f,v:g})),g=(g+i)%1;return h},b.readability=function(a,c){var d=b(a).toRgb(),e=b(c).toRgb(),f=(299*d.r+587*d.g+114*d.b)/1e3,g=(299*e.r+587*e.g+114*e.b)/1e3,h=Math.max(d.r,e.r)-Math.min(d.r,e.r)+Math.max(d.g,e.g)-Math.min(d.g,e.g)+Math.max(d.b,e.b)-Math.min(d.b,e.b);return{brightness:Math.abs(f-g),color:h}},b.readable=function(a,c){var d=b.readability(a,c);return d.brightness>125&&d.color>500},b.mostReadable=function(a,c){for(var d=null,e=0,f=!1,g=0;g125&&h.color>500,j=3*(h.brightness/125)+h.color/500;(i&&!f||i&&f&&j>e||!i&&!f&&j>e)&&(f=i,e=j,d=b(c[g]))}return d};var B=b.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"},C=b.hexNames=j(B),D=function(){var a="[-\\+]?\\d+%?",b="[-\\+]?\\d*\\.\\d+%?",c="(?:"+b+")|(?:"+a+")",d="[\\s|\\(]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")\\s*\\)?",e="[\\s|\\(]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")\\s*\\)?";return{rgb:new RegExp("rgb"+d),rgba:new RegExp("rgba"+e),hsl:new RegExp("hsl"+d),hsla:new RegExp("hsla"+e),hsv:new RegExp("hsv"+d),hex3:/^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/}}();a.tinycolor=b}();var u=a.tinycolor;b(function(){b.fn.spectrum.load&&b.fn.spectrum.processNativeColorInputs()})}(window,jQuery),function(){var a=$.namespace("pskl.rendering");a.DrawingLoop=function(){this.requestAnimationFrame=this.getRequestAnimationFrameShim_(),this.isRunning=!1,this.previousTime=0,this.callbacks=[]},a.DrawingLoop.prototype.addCallback=function(a,b,c){var d={fn:a,scope:b,args:c};return this.callbacks.push(d),d},a.DrawingLoop.prototype.removeCallback=function(a){var b=this.callbacks.indexOf(a);-1!=b&&this.callbacks.splice(b,1)},a.DrawingLoop.prototype.start=function(){this.isRunning=!0,this.loop_()},a.DrawingLoop.prototype.loop_=function(){var a=Date.now(),b=a-this.previousTime;this.executeCallbacks_(b),this.previousTime=a,this.requestAnimationFrame.call(window,this.loop_.bind(this))},a.DrawingLoop.prototype.executeCallbacks_=function(a){for(var b=0;bd;d++){for(var e=[],f=0;b>f;f++)e.push(Constants.TRANSPARENT_COLOR);c[d]=e}return c},a.Frame.createEmptyFromFrame=function(b){return new a.Frame(b.getWidth(),b.getHeight())},a.Frame.prototype.clone=function(){var b=new a.Frame(this.width,this.height);return b.setPixels(this.getPixels()),b},a.Frame.prototype.getPixels=function(){return this.clonePixels_(this.pixels)},a.Frame.prototype.setPixels=function(a){this.pixels=this.clonePixels_(a),this.version++},a.Frame.prototype.clear=function(){var b=a.Frame.createEmptyPixelGrid_(this.getWidth(),this.getHeight());this.setPixels(b)},a.Frame.prototype.clonePixels_=function(a){for(var b=[],c=0;cd;d++)for(var e=0;c>e;e++)a(this.pixels[d][e],d,e,this)},a.Frame.prototype.getWidth=function(){return this.width},a.Frame.prototype.getHeight=function(){return this.height},a.Frame.prototype.containsPixel=function(a,b){return a>=0&&b>=0&&a0&&a[0].length()>0))throw"Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument";var d=a[0].getFrameAt(0);return c=new pskl.model.Piskel(d.getWidth(),d.getHeight(),b),a.forEach(c.addLayer.bind(c)),c},a.Piskel.prototype.getLayers=function(){return this.layers},a.Piskel.prototype.getHeight=function(){return this.height},a.Piskel.prototype.getWidth=function(){return this.width},a.Piskel.prototype.getLayers=function(){return this.layers},a.Piskel.prototype.getLayerAt=function(a){return this.layers[a]},a.Piskel.prototype.getLayersByName=function(a){return this.layers.filter(function(b){return b.getName()==a})},a.Piskel.prototype.addLayer=function(a){this.layers.push(a)},a.Piskel.prototype.moveLayerUp=function(a){var b=this.layers.indexOf(a);b>-1&&b0&&(this.layers[b]=this.layers[b-1],this.layers[b-1]=a)},a.Piskel.prototype.removeLayer=function(a){var b=this.layers.indexOf(a);-1!=b&&this.layers.splice(b,1)},a.Piskel.prototype.removeLayerAt=function(a){this.layers.splice(a,1)},a.Piskel.prototype.getDescriptor=function(){return this.descriptor},a.Piskel.prototype.setDescriptor=function(a){this.descriptor=a;$(".piskel-name").html(this.descriptor.name)},a.Piskel.prototype.getHash=function(){return this.layers.map(function(a){return a.getHash()}).join("-")}}(),function(){var a=$.namespace("pskl.selection"),b={PASTE:"REPLAY_PASTE",ERASE:"REPLAY_ERASE"};a.SelectionManager=function(a){this.piskelController=a,this.currentSelection=null},a.SelectionManager.prototype.init=function(){$.subscribe(Events.SELECTION_CREATED,$.proxy(this.onSelectionCreated_,this)),$.subscribe(Events.SELECTION_DISMISSED,$.proxy(this.onSelectionDismissed_,this)),$.subscribe(Events.SELECTION_MOVE_REQUEST,$.proxy(this.onSelectionMoved_,this)),pskl.app.shortcutService.addShortcut("ctrl+V",this.paste.bind(this)),pskl.app.shortcutService.addShortcut("ctrl+X",this.cut.bind(this)),pskl.app.shortcutService.addShortcut("ctrl+C",this.copy.bind(this)),pskl.app.shortcutService.addShortcut("del",this.erase.bind(this)),pskl.app.shortcutService.addShortcut("back",this.onBackPressed_.bind(this)),$.subscribe(Events.TOOL_SELECTED,$.proxy(this.onToolSelected_,this))},a.SelectionManager.prototype.cleanSelection_=function(){this.currentSelection&&(this.currentSelection.reset(),this.currentSelection=null)},a.SelectionManager.prototype.onToolSelected_=function(a,b){var c=b instanceof pskl.drawingtools.BaseSelect;c||this.cleanSelection_()},a.SelectionManager.prototype.onSelectionDismissed_=function(){this.cleanSelection_()},a.SelectionManager.prototype.onBackPressed_=function(){return this.currentSelection?void this.erase():!0},a.SelectionManager.prototype.erase=function(){for(var a=this.currentSelection.pixels,c=this.piskelController.getCurrentFrame(),d=0,e=a.length;e>d;d++)c.setPixel(a[d].col,a[d].row,Constants.TRANSPARENT_COLOR);$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY,scope:this,replay:{type:b.ERASE,pixels:JSON.parse(JSON.stringify(a.slice(0)))}})},a.SelectionManager.prototype.cut=function(){if(!this.currentSelection)throw"Bad state for CUT callback in SelectionManager";this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame()),this.erase()},a.SelectionManager.prototype.paste=function(){if(this.currentSelection&&this.currentSelection.hasPastedContent){var a=this.currentSelection.pixels,b=a.filter(function(a){return a.color!==Constants.TRANSPARENT_COLOR});this.pastePixels(b)}},a.SelectionManager.prototype.pastePixels=function(a){var c=this.piskelController.getCurrentFrame();a.forEach(function(a){c.setPixel(a.col,a.row,a.color)}),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY,scope:this,replay:{type:b.PASTE,pixels:JSON.parse(JSON.stringify(a.slice(0)))}})},a.SelectionManager.prototype.replay=function(a,c){var d=c.pixels;d.forEach(function(d){var e=c.type===b.PASTE?d.color:Constants.TRANSPARENT_COLOR;a.setPixel(d.col,d.row,e)})},a.SelectionManager.prototype.copy=function(){if(!this.currentSelection||!this.piskelController.getCurrentFrame())throw"Bad state for CUT callback in SelectionManager";this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame())},a.SelectionManager.prototype.onSelectionCreated_=function(a,b){if(!b)throw"No selection set in SelectionManager";this.currentSelection=b},a.SelectionManager.prototype.onSelectionMoved_=function(a,b,c){if(!this.currentSelection)throw"Bad state: No currentSelection set when trying to move it in SelectionManager";this.currentSelection.move(b,c)}}(),function(){var a=$.namespace("pskl.selection");a.BaseSelection=function(){this.reset()},a.BaseSelection.prototype.reset=function(){this.pixels=[],this.hasPastedContent=!1},a.BaseSelection.prototype.move=function(a,b){for(var c,d=[],e=0,f=this.pixels.length;f>e;e++)c=this.pixels[e],c.col+=a,c.row+=b,d.push(c); -this.pixels=d},a.BaseSelection.prototype.fillSelectionFromFrame=function(a){this.pixels.forEach(function(b){b.color=a.getPixel(b.col,b.row)}),this.hasPastedContent=!0}}(),function(){var a=$.namespace("pskl.selection");a.RectangularSelection=function(a,b,c,d){this.pixels=pskl.PixelUtils.getRectanglePixels(a,b,c,d)},pskl.utils.inherit(a.RectangularSelection,a.BaseSelection)}(),function(){var a=$.namespace("pskl.selection");a.ShapeSelection=function(a){this.pixels=a},pskl.utils.inherit(a.ShapeSelection,a.BaseSelection)}(),function(){var a=$.namespace("pskl.rendering");a.AbstractRenderer=function(){},a.AbstractRenderer.prototype.clear=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.render=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getCoordinates=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setGridWidth=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getGridWidth=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setZoom=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getZoom=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setOffset=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getOffset=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setDisplaySize=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getDisplaySize=Constants.ABSTRACT_FUNCTION}(),function(){var a=$.namespace("pskl.rendering");a.CompositeRenderer=function(){this.renderers=[]},pskl.utils.inherit(pskl.rendering.CompositeRenderer,pskl.rendering.AbstractRenderer),a.CompositeRenderer.prototype.add=function(a){return this.renderers.push(a),this},a.CompositeRenderer.prototype.clear=function(){this.renderers.forEach(function(a){a.clear()})},a.CompositeRenderer.prototype.setZoom=function(a){this.renderers.forEach(function(b){b.setZoom(a)})},a.CompositeRenderer.prototype.getZoom=function(){return this.getSampleRenderer_().getZoom()},a.CompositeRenderer.prototype.setDisplaySize=function(a,b){this.renderers.forEach(function(c){c.setDisplaySize(a,b)})},a.CompositeRenderer.prototype.getDisplaySize=function(){return this.getSampleRenderer_().getDisplaySize()},a.CompositeRenderer.prototype.setOffset=function(a,b){this.renderers.forEach(function(c){c.setOffset(a,b)})},a.CompositeRenderer.prototype.getOffset=function(){return this.getSampleRenderer_().getOffset()},a.CompositeRenderer.prototype.setGridWidth=function(a){this.renderers.forEach(function(b){b.setGridWidth(a)})},a.CompositeRenderer.prototype.getGridWidth=function(){return this.getSampleRenderer_().getGridWidth()},a.CompositeRenderer.prototype.getSampleRenderer_=function(){if(this.renderers.length>0)return this.renderers[0];throw"Renderer manager is empty"}}(),function(){var a=$.namespace("pskl.rendering.layer");a.LayersRenderer=function(a,b,c){pskl.rendering.CompositeRenderer.call(this),this.piskelController=c,this.belowRenderer=new pskl.rendering.frame.FrameRenderer(a,b,["layers-canvas","layers-below-canvas"]),this.aboveRenderer=new pskl.rendering.frame.FrameRenderer(a,b,["layers-canvas","layers-above-canvas"]),this.add(this.belowRenderer),this.add(this.aboveRenderer),this.serializedRendering="",$.subscribe(Events.PISKEL_RESET,this.flush.bind(this))},pskl.utils.inherit(pskl.rendering.layer.LayersRenderer,pskl.rendering.CompositeRenderer),a.LayersRenderer.prototype.render=function(){var a=this.getOffset(),b=this.getDisplaySize(),c=this.piskelController.getLayers(),d=this.piskelController.getCurrentFrameIndex(),e=this.piskelController.getCurrentLayerIndex(),f=c.slice(0,e),g=c.slice(e+1,c.length),h=[this.getZoom(),this.getGridWidth(),a.x,a.y,b.width,b.height,this.getHashForLayersAt_(d,f),this.getHashForLayersAt_(d,g),c.length].join("-");if(this.serializedRendering!=h){if(this.serializedRendering=h,this.clear(),f.length>0){var i=this.getFrameForLayersAt_(d,f);this.belowRenderer.render(i)}if(g.length>0){var j=this.getFrameForLayersAt_(d,g);this.aboveRenderer.render(j)}}},a.LayersRenderer.prototype.setDisplaySize=function(a,b){var c=this.getDisplaySize();(c.width!==a||c.height!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.LayersRenderer.prototype.getFrameForLayersAt_=function(a,b){var c=b.map(function(b){return b.getFrameAt(a)});return pskl.utils.FrameUtils.merge(c)},a.LayersRenderer.prototype.getHashForLayersAt_=function(a,b){var c=b.map(function(b){return b.getFrameAt(a).getHash()});return c.join("-")},a.LayersRenderer.prototype.flush=function(){this.serializedRendering=""}}(),function(){var a=$.namespace("pskl.rendering.frame");a.FrameRenderer=function(a,b,c){if(this.defaultRenderingOptions={supportGridRendering:!1,zoom:1},b=$.extend(!0,{},this.defaultRenderingOptions,b),void 0===a)throw"Bad FrameRenderer initialization. undefined.";if(isNaN(b.zoom))throw"Bad FrameRenderer initialization. not well defined.";this.container=a,this.zoom=b.zoom,this.offset={x:0,y:0},this.margin={x:0,y:0},this.supportGridRendering=b.supportGridRendering,this.classes=c||[],this.classes.push("canvas"),this.canvas=null,this.displayCanvas=null,this.setDisplaySize(b.width,b.height),this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)),$.subscribe(Events.USER_SETTINGS_CHANGED,this.onUserSettingsChange_.bind(this))},pskl.utils.inherit(pskl.rendering.frame.FrameRenderer,pskl.rendering.AbstractRenderer),a.FrameRenderer.prototype.render=function(a){a&&(this.clear(),this.renderFrame_(a))},a.FrameRenderer.prototype.clear=function(){pskl.CanvasUtils.clear(this.canvas),pskl.CanvasUtils.clear(this.displayCanvas)},a.FrameRenderer.prototype.setZoom=function(a){if(a>Constants.MINIMUM_ZOOM){var b=this.offset.x+this.displayWidth/(2*this.zoom),c=this.offset.y+this.displayHeight/(2*this.zoom);this.zoom=a,this.setOffset(b-this.displayWidth/(2*this.zoom),c-this.displayHeight/(2*this.zoom))}},a.FrameRenderer.prototype.getZoom=function(){return this.zoom},a.FrameRenderer.prototype.setDisplaySize=function(a,b){this.displayWidth=a,this.displayHeight=b,this.displayCanvas&&($(this.displayCanvas).remove(),this.displayCanvas=null),this.createDisplayCanvas_()},a.FrameRenderer.prototype.getDisplaySize=function(){return{height:this.displayHeight,width:this.displayWidth}},a.FrameRenderer.prototype.getOffset=function(){return{x:this.offset.x,y:this.offset.y}},a.FrameRenderer.prototype.setOffset=function(a,b){var c=pskl.app.piskelController.getWidth(),d=pskl.app.piskelController.getHeight(),e=c-this.displayWidth/this.zoom;a=pskl.utils.Math.minmax(a,0,e);var f=d-this.displayHeight/this.zoom;b=pskl.utils.Math.minmax(b,0,f),this.offset.x=a,this.offset.y=b},a.FrameRenderer.prototype.setGridWidth=function(a){this.gridWidth_=a},a.FrameRenderer.prototype.getGridWidth=function(){return this.supportGridRendering?this.gridWidth_:0},a.FrameRenderer.prototype.updateMargins_=function(a){var b=this.displayWidth-this.zoom*a.getWidth();this.margin.x=Math.max(0,b)/2;var c=this.displayHeight-this.zoom*a.getHeight();this.margin.y=Math.max(0,c)/2},a.FrameRenderer.prototype.createDisplayCanvas_=function(){var a=this.displayHeight,b=this.displayWidth;this.displayCanvas=pskl.CanvasUtils.createCanvas(b,a,this.classes),pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas),this.container.append(this.displayCanvas)},a.FrameRenderer.prototype.onUserSettingsChange_=function(a,b,c){b==pskl.UserSettings.GRID_WIDTH&&this.setGridWidth(c)},a.FrameRenderer.prototype.renderPixel_=function(a,b,c,d){a!=Constants.TRANSPARENT_COLOR&&(d.fillStyle=a,d.fillRect(b,c,1,1))},a.FrameRenderer.prototype.getCoordinates=function(a,b){var c=this.container.offset();a-=c.left,b-=c.top,a-=this.margin.x,b-=this.margin.y;var d=this.zoom;return a+=this.offset.x*d,b+=this.offset.y*d,{x:Math.floor(a/d),y:Math.floor(b/d)}},a.FrameRenderer.prototype.reverseCoordinates=function(a,b){var c=this.zoom;a*=c,b*=c,a-=this.offset.x*c,b-=this.offset.y*c,a+=this.margin.x,b+=this.margin.y;var d=this.container.offset();return a+=d.left,b+=d.top,{x:a+c/2,y:b+c/2}},a.FrameRenderer.prototype.renderFrame_=function(a){this.canvas&&a.getWidth()==this.canvas.width&&a.getHeight()==this.canvas.height||(this.canvas=pskl.CanvasUtils.createCanvas(a.getWidth(),a.getHeight()));for(var b=this.canvas.getContext("2d"),c=0,d=a.getWidth();d>c;c++)for(var e=0,f=a.getHeight();f>e;e++){var g=a.getPixel(c,e);this.renderPixel_(g,c,e,b)}this.updateMargins_(a);var h=this.displayCanvas.getContext("2d");h.save(),this.canvas.width*this.zoom0;if(k||i){var l=pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas,this.zoom,j);h.drawImage(l,0,0)}else h.scale(this.zoom,this.zoom),h.drawImage(this.canvas,0,0);h.restore()}}(),function(){var a=$.namespace("pskl.rendering");a.OnionSkinRenderer=function(a,b,c){pskl.rendering.CompositeRenderer.call(this),this.piskelController=c,this.renderer=new pskl.rendering.frame.FrameRenderer(a,b,["onion-skin-canvas"]),this.add(this.renderer),this.serializedRendering=""},pskl.utils.inherit(pskl.rendering.OnionSkinRenderer,pskl.rendering.CompositeRenderer),a.OnionSkinRenderer.prototype.render=function(){var a=this.getOffset(),b=this.getDisplaySize(),c=this.piskelController.getLayers(),d=this.piskelController.getCurrentFrameIndex(),e=[];this.addFrameAtIndexToArray_(d-1,e),this.addFrameAtIndexToArray_(d+1,e);var f=[this.getZoom(),this.getGridWidth(),a.x,a.y,b.width,b.height,e.map(function(a){return a.getHash()}).join("-"),c.length].join("-");if(this.serializedRendering!=f&&(this.serializedRendering=f,e.length>0)){this.clear();var g=pskl.utils.FrameUtils.merge(e);this.renderer.render(g)}},a.OnionSkinRenderer.prototype.addFrameAtIndexToArray_=function(a,b){var c=this.piskelController.getCurrentLayer();this.piskelController.hasFrameAt(a)&&b.push(c.getFrameAt(a))},a.OnionSkinRenderer.prototype.setDisplaySize=function(a,b){var c=this.getDisplaySize();(c.width!==a||c.height!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.OnionSkinRenderer.prototype.flush=function(){this.serializedRendering=""}}(),function(){var a=$.namespace("pskl.rendering.frame");a.TiledFrameRenderer=function(a,b){this.container=a,this.setZoom(b),this.displayContainer=document.createElement("div"),this.displayContainer.classList.add("tiled-frame-container"),a.get(0).appendChild(this.displayContainer),this.cachedFrameProcessor=new pskl.model.frame.CachedFrameProcessor,this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this))},a.TiledFrameRenderer.prototype.frameToDataUrl_=function(a){var b=new pskl.utils.FrameUtils.toImage(a,this.zoom);return b.toDataURL("image/png")},a.TiledFrameRenderer.prototype.render=function(a){var b=this.cachedFrameProcessor.get(a,this.zoom);this.displayContainer.style.backgroundImage="url("+b+")"},a.TiledFrameRenderer.prototype.show=function(){this.displayContainer&&(this.displayContainer.style.display="block")},a.TiledFrameRenderer.prototype.setZoom=function(a){this.zoom=a},a.TiledFrameRenderer.prototype.getZoom=function(){return this.zoom}}(),function(){var a=$.namespace("pskl.rendering.frame");a.CachedFrameRenderer=function(a,b,c){pskl.rendering.frame.FrameRenderer.call(this,a,b,c),this.serializedFrame=""},pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer,pskl.rendering.frame.FrameRenderer),a.CachedFrameRenderer.prototype.setDisplaySize=function(a,b){(this.displayWidth!==a||this.displayHeight!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.CachedFrameRenderer.prototype.render=function(a){var b=this.getOffset(),c=this.getDisplaySize(),d=[this.getZoom(),this.getGridWidth(),b.x,b.y,c.width,c.height,a.getHash()].join("-");this.serializedFrame!=d&&(this.serializedFrame=d,this.superclass.render.call(this,a))}}(),function(){var a=$.namespace("pskl.rendering");a.CanvasRenderer=function(a,b){this.frame=a,this.zoom=b,this.transparentColor_="white"},a.CanvasRenderer.prototype.drawTransparentAs=function(a){this.transparentColor_=a},a.CanvasRenderer.prototype.render=function(){var a=this.createCanvas_(),b=a.getContext("2d");this.frame.forEachPixel(function(a,c,d){this.renderPixel_(a,c,d,b)}.bind(this));var c=this.createCanvas_(this.zoom),d=c.getContext("2d");return pskl.CanvasUtils.disableImageSmoothing(c),d.scale(this.zoom,this.zoom),d.drawImage(a,0,0),c},a.CanvasRenderer.prototype.renderPixel_=function(a,b,c,d){a==Constants.TRANSPARENT_COLOR&&(a=this.transparentColor_),d.fillStyle=a,d.fillRect(b,c,1,1)},a.CanvasRenderer.prototype.createCanvas_=function(a){a=a||1;var b=this.frame.getWidth()*a,c=this.frame.getHeight()*a;return pskl.CanvasUtils.createCanvas(b,c)}}(),function(){var a=$.namespace("pskl.rendering");a.FramesheetRenderer=function(a){if(!(a.length>0))throw"FramesheetRenderer : Invalid argument : frames is empty";this.frames=a},a.FramesheetRenderer.prototype.renderAsCanvas=function(){for(var a=this.createCanvas_(),b=0;b=a&&this.currentFrameIndex>0&&this.setCurrentFrameIndex(this.currentFrameIndex-1)},a.PiskelController.prototype.duplicateCurrentFrame=function(){this.duplicateFrameAt(this.currentFrameIndex)},a.PiskelController.prototype.duplicateFrameAt=function(a){this.getLayers().forEach(function(b){b.duplicateFrameAt(a)}),this.setCurrentFrameIndex(a+1)},a.PiskelController.prototype.moveFrame=function(a,b){this.getLayers().forEach(function(c){c.moveFrame(a,b)})},a.PiskelController.prototype.getFrameCount=function(){var a=this.piskel.getLayerAt(0);return a.length()},a.PiskelController.prototype.setCurrentFrameIndex=function(a){this.hasFrameAt(a)?this.currentFrameIndex=a:window.console.error("Could not set current frame index to "+a)},a.PiskelController.prototype.selectNextFrame=function(){var a=this.currentFrameIndex+1;a=0&&this.setCurrentFrameIndex(a)},a.PiskelController.prototype.setCurrentLayerIndex=function(a){this.hasLayerAt(a)?this.currentLayerIndex=a:window.console.error("Could not set current layer index to "+a)},a.PiskelController.prototype.selectLayer=function(a){var b=this.getLayers().indexOf(a);-1!=b&&this.setCurrentLayerIndex(b)},a.PiskelController.prototype.renameLayerAt=function(a,b){var c=this.getLayerByIndex(a);c&&c.setName(b)},a.PiskelController.prototype.generateLayerName_=function(){for(var a="Layer "+this.layerIdCounter;this.hasLayerForName_(a);)this.layerIdCounter++,a="Layer "+this.layerIdCounter;return a},a.PiskelController.prototype.createLayer=function(a){if(a||(a=this.generateLayerName_()),this.hasLayerForName_(a))throw"Layer name should be unique";for(var b=new pskl.model.Layer(a),c=0;c0},a.PiskelController.prototype.moveLayerUp=function(){var a=this.getCurrentLayer();this.piskel.moveLayerUp(a),this.selectLayer(a)},a.PiskelController.prototype.moveLayerDown=function(){var a=this.getCurrentLayer();this.piskel.moveLayerDown(a),this.selectLayer(a)},a.PiskelController.prototype.removeLayerAt=function(a){if(this.getLayers().length>1){var b=this.getLayerAt(a);b&&(this.piskel.removeLayer(b),this.setCurrentLayerIndex(0))}},a.PiskelController.prototype.serialize=function(a){return pskl.utils.Serializer.serializePiskel(this.piskel,a)}}(),function(){var a=$.namespace("pskl.controller.piskel");a.PublicPiskelController=function(a){this.piskelController=a,pskl.utils.wrap(this,this.piskelController)},a.PublicPiskelController.prototype.init=function(){pskl.app.shortcutService.addShortcut("up",this.selectPreviousFrame.bind(this)),pskl.app.shortcutService.addShortcut("down",this.selectNextFrame.bind(this)),pskl.app.shortcutService.addShortcut("n",this.addFrameAtCurrentIndex.bind(this)),pskl.app.shortcutService.addShortcut("shift+n",this.duplicateCurrentFrame.bind(this))},a.PublicPiskelController.prototype.setPiskel=function(a,b){this.piskelController.setPiskel(a,b),$.publish(Events.FRAME_SIZE_CHANGED),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})},a.PublicPiskelController.prototype.addFrame=function(){this.addFrameAt(this.getFrameCount())},a.PublicPiskelController.prototype.addFrameAtCurrentIndex=function(){this.addFrameAt(this.getCurrentFrameIndex())},a.PublicPiskelController.prototype.addFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.addFrameAt,[a]),this.piskelController.addFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.removeFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.removeFrameAt,[a]),this.piskelController.removeFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.duplicateCurrentFrame=function(){this.duplicateFrameAt(this.getCurrentFrameIndex())},a.PublicPiskelController.prototype.replay=function(a,b){b.fn.apply(this.piskelController,b.args)},a.PublicPiskelController.prototype.duplicateFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt,[a]),this.piskelController.duplicateFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveFrame=function(a,b){this.raiseSaveStateEvent_(this.piskelController.moveFrame,[a,b]),this.piskelController.moveFrame(a,b),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.setCurrentFrameIndex=function(a){this.piskelController.setCurrentFrameIndex(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectNextFrame=function(){this.piskelController.selectNextFrame(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectPreviousFrame=function(){this.piskelController.selectPreviousFrame(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.setCurrentLayerIndex=function(a){this.piskelController.setCurrentLayerIndex(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectLayer=function(a){this.piskelController.selectLayer(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.renameLayerAt=function(a,b){this.raiseSaveStateEvent_(this.piskelController.renameLayerAt,[a,b]),this.piskelController.renameLayerAt(a,b)},a.PublicPiskelController.prototype.createLayer=function(a){this.raiseSaveStateEvent_(this.piskelController.createLayer,[a]),this.piskelController.createLayer(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveLayerUp=function(){this.raiseSaveStateEvent_(this.piskelController.moveLayerUp,[]),this.piskelController.moveLayerUp(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveLayerDown=function(){this.raiseSaveStateEvent_(this.piskelController.moveLayerDown,[]),this.piskelController.moveLayerDown(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.removeCurrentLayer=function(){var a=this.getCurrentLayerIndex();this.raiseSaveStateEvent_(this.piskelController.removeLayerAt,[a]),this.piskelController.removeLayerAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.getCurrentLayerIndex=function(){return this.piskelController.getCurrentLayerIndex()},a.PublicPiskelController.prototype.getCurrentFrameIndex=function(){return this.piskelController.currentFrameIndex},a.PublicPiskelController.prototype.getPiskel=function(){return this.piskelController.piskel},a.PublicPiskelController.prototype.raiseSaveStateEvent_=function(a,b){$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY_NO_SNAPSHOT,scope:this,replay:{fn:a,args:b}})}}(),function(){var a=$.namespace("pskl.controller");a.CursorCoordinatesController=function(a){this.piskelController=a,this.origin=null,this.coordinates={x:-1,y:-1}},a.CursorCoordinatesController.prototype.init=function(){this.coordinatesContainer=document.querySelector(".cursor-coordinates"),$.subscribe(Events.CURSOR_MOVED,this.onCursorMoved_.bind(this)),$.subscribe(Events.DRAG_START,this.onDragStart_.bind(this)),$.subscribe(Events.DRAG_END,this.onDragEnd_.bind(this)),$.subscribe(Events.FRAME_SIZE_CHANGED,this.redraw.bind(this)),this.redraw()},a.CursorCoordinatesController.prototype.redraw=function(){var a="";this.origin&&(a+=this.origin.x+":"+this.origin.y+" to ");var b=this.coordinates.x,c=this.coordinates.y,d=this.piskelController.getCurrentFrame();if(d.containsPixel(b,c)&&(a+=b+":"+c,this.origin)){var e=Math.abs(b-this.origin.x)+1,f=Math.abs(c-this.origin.y)+1;a+=" ("+e+"x"+f+")"}this.coordinatesContainer.innerHTML=this.getFrameSizeHTML_()+a},a.CursorCoordinatesController.prototype.getFrameSizeHTML_=function(){var a=this.piskelController.getWidth(),b=this.piskelController.getHeight();return"["+a+"x"+b+"] "},a.CursorCoordinatesController.prototype.onCursorMoved_=function(a,b,c){this.coordinates={x:b,y:c},this.redraw()},a.CursorCoordinatesController.prototype.onDragStart_=function(a,b,c){this.origin={x:b,y:c},this.redraw()},a.CursorCoordinatesController.prototype.onDragEnd_=function(){this.origin=null,this.redraw()}}(),function(){var a=$.namespace("pskl.controller");a.DrawingController=function(a,b,c){this.piskelController=a,this.paletteController=b,this.overlayFrame=pskl.model.Frame.createEmptyFromFrame(a.getCurrentFrame()),this.container=c;var d={zoom:this.calculateZoom_(),supportGridRendering:!0,height:this.getContainerHeight_(),width:this.getContainerWidth_(),xOffset:0,yOffset:0};this.overlayRenderer=new pskl.rendering.frame.CachedFrameRenderer(this.container,d,["canvas-overlay"]),this.renderer=new pskl.rendering.frame.CachedFrameRenderer(this.container,d,["drawing-canvas"]),this.onionSkinRenderer=new pskl.rendering.OnionSkinRenderer(this.container,d,a),this.layersRenderer=new pskl.rendering.layer.LayersRenderer(this.container,d,a),this.compositeRenderer=new pskl.rendering.CompositeRenderer,this.compositeRenderer.add(this.overlayRenderer).add(this.renderer).add(this.layersRenderer).add(this.onionSkinRenderer),this.isClicked=!1,this.previousMousemoveTime=0,this.currentToolBehavior=null,this.currentMouseButton_=Constants.LEFT_BUTTON},a.DrawingController.prototype.init=function(){this.initMouseBehavior(),$.subscribe(Events.TOOL_SELECTED,$.proxy(function(a,b){this.currentToolBehavior=b,this.overlayFrame.clear()},this)),$(window).resize($.proxy(this.startResizeTimer_,this)),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this)),$.subscribe(Events.FRAME_SIZE_CHANGED,$.proxy(this.onFrameSizeChanged_,this)),pskl.app.shortcutService.addShortcut("0",this.resetZoom_.bind(this)),pskl.app.shortcutService.addShortcut("+",this.increaseZoom_.bind(this,1)),pskl.app.shortcutService.addShortcut("-",this.decreaseZoom_.bind(this,1)),window.setTimeout(this.afterWindowResize_.bind(this),100)},a.DrawingController.prototype.initMouseBehavior=function(){var a=$("body");this.container.mousedown($.proxy(this.onMousedown_,this)),pskl.utils.UserAgent.isChrome?this.container.on("mousewheel",$.proxy(this.onMousewheel_,this)):this.container.on("wheel",$.proxy(this.onMousewheel_,this)),window.addEventListener("mouseup",this.onMouseup_.bind(this)),window.addEventListener("mousemove",this.onMousemove_.bind(this)),window.addEventListener("keyup",this.onKeyup_.bind(this)),a.contextmenu(this.onCanvasContextMenu_)},a.DrawingController.prototype.startResizeTimer_=function(){this.resizeTimer&&window.clearInterval(this.resizeTimer),this.resizeTimer=window.setTimeout($.proxy(this.afterWindowResize_,this),200)},a.DrawingController.prototype.afterWindowResize_=function(){var a=this.compositeRenderer.getDisplaySize().width;this.compositeRenderer.setDisplaySize(this.getContainerWidth_(),this.getContainerHeight_()),this.centerColumnWrapperHorizontally_();var b=this.compositeRenderer.getDisplaySize().width/a,c=b*this.compositeRenderer.getZoom();this.compositeRenderer.setZoom(c),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.SHOW_GRID?console.warn("DrawingController:onUserSettingsChange_ not implemented !"):(b==pskl.UserSettings.ONION_SKIN||b==pskl.UserSettings.LAYER_PREVIEW)&&(this.onionSkinRenderer.clear(),this.onionSkinRenderer.flush(),this.layersRenderer.clear(),this.layersRenderer.flush(),this.render())},a.DrawingController.prototype.onFrameSizeChanged_=function(){this.compositeRenderer.setDisplaySize(this.getContainerWidth_(),this.getContainerHeight_()),this.centerColumnWrapperHorizontally_(),this.compositeRenderer.setZoom(this.calculateZoom_()),this.compositeRenderer.setOffset(0,0),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onMousedown_=function(a){$.publish(Events.MOUSE_EVENT,[a,this]);var b=this.piskelController.getCurrentFrame(),c=this.getSpriteCoordinates(a.clientX,a.clientY);a.button===Constants.MIDDLE_BUTTON?b.containsPixel(c.x,c.y)&&$.publish(Events.SELECT_PRIMARY_COLOR,[b.getPixel(c.x,c.y)]):(this.isClicked=!0,this.setCurrentButton(a),this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame),this.currentToolBehavior.applyToolAt(c.x,c.y,this.getCurrentColor_(),b,this.overlayFrame,a))},a.DrawingController.prototype.onMousemove_=function(a){this._clientX=a.clientX,this._clientY=a.clientY;var b=(new Date).getTime();b-this.previousMousemoveTime>Constants.MOUSEMOVE_THROTTLING&&(this.moveTool_(this._clientX,this._clientY,a),this.previousMousemoveTime=b)},a.DrawingController.prototype.resetZoom_=function(){this.setZoom_(this.calculateZoom_())},a.DrawingController.prototype.increaseZoom_=function(a){var b=(a||1)*this.getZoomStep_();this.setZoom_(this.renderer.getZoom()+b)},a.DrawingController.prototype.decreaseZoom_=function(a){var b=(a||1)*this.getZoomStep_();this.setZoom_(this.renderer.getZoom()-b)},a.DrawingController.prototype.getZoomStep_=function(){return this.calculateZoom_()/10},a.DrawingController.prototype.setZoom_=function(a){this.compositeRenderer.setZoom(a),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onKeyup_=function(a){this.moveTool_(this._clientX,this._clientY,a)},a.DrawingController.prototype.moveTool_=function(a,b,c){var d=this.getSpriteCoordinates(a,b),e=this.piskelController.getCurrentFrame();this.isClicked?($.publish(Events.MOUSE_EVENT,[c,this]),this.currentToolBehavior.moveToolAt(0|d.x,0|d.y,this.getCurrentColor_(),e,this.overlayFrame,c)):this.currentToolBehavior.moveUnactiveToolAt(d.x,d.y,this.getCurrentColor_(),e,this.overlayFrame,c),$.publish(Events.CURSOR_MOVED,[d.x,d.y])},a.DrawingController.prototype.onMousewheel_=function(a){var b=a.originalEvent,c=b.wheelDeltaY||-2*b.deltaY,d=Math.abs(c/120);c>0?this.increaseZoom_(d):0>c&&this.decreaseZoom_(d)},a.DrawingController.prototype.onMouseup_=function(a){if(this.isClicked){$.publish(Events.MOUSE_EVENT,[a,this]),this.isClicked=!1,this.setCurrentButton(a);var b=this.getSpriteCoordinates(a.clientX,a.clientY);this.currentToolBehavior.releaseToolAt(b.x,b.y,this.getCurrentColor_(),this.piskelController.getCurrentFrame(),this.overlayFrame,a),$.publish(Events.TOOL_RELEASED)}},a.DrawingController.prototype.getSpriteCoordinates=function(a,b){return this.renderer.getCoordinates(a,b)},a.DrawingController.prototype.getScreenCoordinates=function(a,b){return this.renderer.reverseCoordinates(a,b)},a.DrawingController.prototype.setCurrentButton=function(a){this.currentMouseButton_=a.button},a.DrawingController.prototype.getCurrentColor_=function(){return this.currentMouseButton_==Constants.RIGHT_BUTTON?this.paletteController.getSecondaryColor():this.currentMouseButton_==Constants.LEFT_BUTTON?this.paletteController.getPrimaryColor():Constants.DEFAULT_PEN_COLOR},a.DrawingController.prototype.onCanvasContextMenu_=function(a){return $(a.target).closest("#drawing-canvas-container").length?(a.preventDefault(),a.stopPropagation(),a.cancelBubble=!0,!1):void 0},a.DrawingController.prototype.render=function(){var a=this.piskelController.getCurrentFrame();a.isSameSize(this.overlayFrame)||(this.overlayFrame=pskl.model.Frame.createEmptyFromFrame(a)),pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)&&this.onionSkinRenderer.render(),pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)&&this.layersRenderer.render(),this.renderer.render(a),this.overlayRenderer.render(this.overlayFrame)},a.DrawingController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame().getHeight(),b=this.piskelController.getCurrentFrame().getWidth();return Math.min(this.getAvailableWidth_()/b,this.getAvailableHeight_()/a)},a.DrawingController.prototype.getAvailableHeight_=function(){return $("#main-wrapper").height()},a.DrawingController.prototype.getAvailableWidth_=function(){var a=$(".left-column").outerWidth(!0),b=$(".right-column").outerWidth(!0),c=$("#tool-section").outerWidth(!0),d=$("#application-action-section").outerWidth(!0),e=$("#main-wrapper").width()-a-b-c-d,f=10; -return e-f},a.DrawingController.prototype.getContainerHeight_=function(){return this.calculateZoom_()*this.piskelController.getCurrentFrame().getHeight()},a.DrawingController.prototype.getContainerWidth_=function(){return this.calculateZoom_()*this.piskelController.getCurrentFrame().getWidth()},a.DrawingController.prototype.centerColumnWrapperHorizontally_=function(){var a=this.getContainerHeight_(),b=Math.floor(($("#main-wrapper").height()-a)/2);$("#column-wrapper").css({top:b+"px"})},a.DrawingController.prototype.getRenderer=function(){return this.compositeRenderer},a.DrawingController.prototype.setOffset=function(a,b){this.compositeRenderer.setOffset(a,b),$.publish(Events.ZOOM_CHANGED)}}(),function(){var a=$.namespace("pskl.controller"),b={SELECT:"select",CLONE:"clone",DELETE:"delete",NEW_FRAME:"newframe"};a.PreviewFilmController=function(a,b){this.piskelController=a,this.container=b,this.refreshZoom_(),this.redrawFlag=!0,this.cachedFrameProcessor=new pskl.model.frame.CachedFrameProcessor,this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)),this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this))},a.PreviewFilmController.prototype.init=function(){$.subscribe(Events.TOOL_RELEASED,this.flagForRedraw_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.flagForRedraw_.bind(this)),$.subscribe(Events.USER_SETTINGS_CHANGED,this.flagForRedraw_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.refreshZoom_.bind(this)),$("#preview-list-scroller").scroll(this.updateScrollerOverflows.bind(this)),this.container.get(0).addEventListener("click",this.onContainerClick_.bind(this)),this.updateScrollerOverflows()},a.PreviewFilmController.prototype.flagForRedraw_=function(){this.redrawFlag=!0},a.PreviewFilmController.prototype.refreshZoom_=function(){this.zoom=this.calculateZoom_()},a.PreviewFilmController.prototype.render=function(){this.redrawFlag&&(this.createPreviews_(),this.redrawFlag=!1)},a.PreviewFilmController.prototype.updateScrollerOverflows=function(){var a=$("#preview-list-scroller"),b=a.height(),c=a.scrollTop(),d=$("#preview-list").height(),e=$(".top-overflow").height(),f=!1,g=!1;if(d>b){c>e&&(f=!0);var h=d-c-b;h>e&&(g=!0)}var i=$("#preview-list-wrapper");i.toggleClass("top-overflow-visible",f),i.toggleClass("bottom-overflow-visible",g)},a.PreviewFilmController.prototype.onContainerClick_=function(a){var c=pskl.utils.Dom.getParentWithData(a.target,"tileAction");if(c){var d=c.dataset.tileAction,e=parseInt(c.dataset.tileNumber,10);d===b.CLONE?(this.piskelController.duplicateFrameAt(e),this.updateScrollerOverflows()):d===b.DELETE?(this.piskelController.removeFrameAt(e),this.updateScrollerOverflows()):d===b.SELECT?this.piskelController.setCurrentFrameIndex(e):d===b.NEW_FRAME&&(this.piskelController.addFrame(),this.updateScrollerOverflows())}},a.PreviewFilmController.prototype.createPreviews_=function(){this.container.html(""),$(".tooltip").remove();for(var a=this.piskelController.getFrameCount(),c=0,d=a;d>c;c++)this.container.append(this.createPreviewTile_(c));var e=document.createElement("div");e.id="add-frame-action",e.className="add-frame-action",e.setAttribute("data-tile-action",b.NEW_FRAME),e.innerHTML="

        Add new frame

        ",this.container.append(e);var f=a>1;f&&this.initDragndropBehavior_(),this.updateScrollerOverflows()},a.PreviewFilmController.prototype.initDragndropBehavior_=function(){$("#preview-list").sortable({placeholder:"preview-tile-drop-proxy",update:$.proxy(this.onUpdate_,this),items:".preview-tile"}),$("#preview-list").disableSelection()},a.PreviewFilmController.prototype.onUpdate_=function(a,b){var c=parseInt(b.item.data("tile-number"),10),d=$(".preview-tile").index(b.item);this.piskelController.moveFrame(c,d),this.piskelController.setCurrentFrameIndex(d)},a.PreviewFilmController.prototype.createPreviewTile_=function(a){var c=this.piskelController.getCurrentLayer().getFrameAt(a),d=document.createElement("li");d.setAttribute("data-tile-number",a),d.setAttribute("data-tile-action",b.SELECT),d.classList.add("preview-tile"),this.piskelController.getCurrentFrame()==c&&d.classList.add("selected");var e=document.createElement("div");e.classList.add("canvas-container",pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND));var f=document.createElement("div");f.className="canvas-background",e.appendChild(f);var g=document.createElement("button");if(g.setAttribute("rel","tooltip"),g.setAttribute("data-placement","right"),g.setAttribute("data-tile-number",a),g.setAttribute("data-tile-action",b.CLONE),g.setAttribute("title","Duplicate this frame"),g.className="tile-overlay duplicate-frame-action",d.appendChild(g),e.appendChild(this.getCanvasForFrame(c)),d.appendChild(e),a>0||this.piskelController.getFrameCount()>1){var h=document.createElement("button");h.setAttribute("rel","tooltip"),h.setAttribute("data-placement","right"),h.setAttribute("title","Delete this frame"),h.setAttribute("data-tile-number",a),h.setAttribute("data-tile-action",b.DELETE),h.className="tile-overlay delete-frame-action",d.appendChild(h);var i=document.createElement("div");i.className="tile-overlay dnd-action",d.appendChild(i)}var j=document.createElement("div");return j.className="tile-overlay tile-count",j.innerHTML=a+1,d.appendChild(j),d},a.PreviewFilmController.prototype.getCanvasForFrame=function(a){var b=this.cachedFrameProcessor.get(a,this.zoom);return b},a.PreviewFilmController.prototype.frameToPreviewCanvas_=function(a){var b=new pskl.rendering.CanvasRenderer(a,this.zoom);b.drawTransparentAs(Constants.TRANSPARENT_COLOR);var c=b.render();return c.classList.add("tile-view","canvas"),c},a.PreviewFilmController.prototype.clonePreviewCanvas_=function(a){var b=pskl.CanvasUtils.clone(a);return b.classList.add("tile-view","canvas"),b},a.PreviewFilmController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame(),b=a.getHeight(),c=a.getWidth();return Math.min(Constants.PREVIEW_FILM_SIZE/b,Constants.PREVIEW_FILM_SIZE/c)}}(),function(){var a=$.namespace("pskl.controller");a.LayersListController=function(a){this.piskelController=a},a.LayersListController.prototype.init=function(){this.layerItemTemplate_=pskl.utils.Template.get("layer-item-template"),this.rootEl=document.querySelector(".layers-list-container"),this.layersListEl=document.querySelector(".layers-list"),this.toggleLayerPreviewEl=document.querySelector(".layers-toggle-preview"),this.rootEl.addEventListener("click",this.onClick_.bind(this)),this.toggleLayerPreviewEl.addEventListener("click",this.toggleLayerPreview_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.renderLayerList_.bind(this)),pskl.app.shortcutService.addShortcut("alt+L",this.toggleLayerPreview_.bind(this)),this.renderLayerList_(),this.updateToggleLayerPreview_(),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this))},a.LayersListController.prototype.renderLayerList_=function(){this.layersListEl.innerHTML="";var a=this.piskelController.getLayers();a.forEach(this.addLayerItem.bind(this))},a.LayersListController.prototype.updateToggleLayerPreview_=function(){var a="layers-toggle-preview-enabled";pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)?this.toggleLayerPreviewEl.classList.add(a):this.toggleLayerPreviewEl.classList.remove(a)},a.LayersListController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.LAYER_PREVIEW&&this.updateToggleLayerPreview_()},a.LayersListController.prototype.addLayerItem=function(a,b){var c=this.piskelController.getCurrentLayer()===a,d=pskl.utils.Template.replace(this.layerItemTemplate_,{layername:a.getName(),layerindex:b,"isselected:current-layer-item":c}),e=pskl.utils.Template.createFromHTML(d);this.layersListEl.insertBefore(e,this.layersListEl.firstChild)},a.LayersListController.prototype.onClick_=function(a){var b,c=a.target||a.srcElement;c.classList.contains("button")?this.onButtonClick_(c):c.classList.contains("layer-item")?(b=c.dataset.layerIndex,this.piskelController.setCurrentLayerIndex(parseInt(b,10))):c.classList.contains("edit-icon")&&(b=c.parentNode.dataset.layerIndex,this.renameLayerAt_(b))},a.LayersListController.prototype.renameLayerAt_=function(a){var b=this.piskelController.getLayerAt(a),c=window.prompt("Please enter the layer name",b.getName());c&&(this.piskelController.renameLayerAt(a,c),this.renderLayerList_())},a.LayersListController.prototype.onButtonClick_=function(a){var b=a.getAttribute("data-action");"up"==b?this.piskelController.moveLayerUp():"down"==b?this.piskelController.moveLayerDown():"add"==b?this.piskelController.createLayer():"delete"==b&&this.piskelController.removeCurrentLayer()},a.LayersListController.prototype.toggleLayerPreview_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW);pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW,!a)}}(),function(){var a=$.namespace("pskl.controller"),b=200;a.AnimatedPreviewController=function(a,b){this.piskelController=a,this.container=b,this.elapsedTime=0,this.currentIndex=0,this.setFPS(Constants.DEFAULT.FPS);this.piskelController.getCurrentFrame();this.renderer=new pskl.rendering.frame.TiledFrameRenderer(this.container)},a.AnimatedPreviewController.prototype.init=function(){$("#preview-fps")[0].addEventListener("change",this.onFPSSliderChange.bind(this)),document.querySelector(".right-column").style.width=Constants.ANIMATED_PREVIEW_WIDTH+"px",this.toggleOnionSkinEl=document.querySelector(".preview-toggle-onion-skin"),this.toggleOnionSkinEl.addEventListener("click",this.toggleOnionSkin_.bind(this)),pskl.app.shortcutService.addShortcut("alt+O",this.toggleOnionSkin_.bind(this)),$.subscribe(Events.FRAME_SIZE_CHANGED,this.onFrameSizeChange_.bind(this)),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this)),this.updateZoom_(),this.updateOnionSkinPreview_()},a.AnimatedPreviewController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.ONION_SKIN?this.updateOnionSkinPreview_():(this.updateZoom_(),this.updateContainerDimensions_())},a.AnimatedPreviewController.prototype.updateOnionSkinPreview_=function(){var a="preview-toggle-onion-skin-enabled";pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)?this.toggleOnionSkinEl.classList.add(a):this.toggleOnionSkinEl.classList.remove(a)},a.AnimatedPreviewController.prototype.updateZoom_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW),b=a?1:this.calculateZoom_();this.renderer.setZoom(b)},a.AnimatedPreviewController.prototype.getZoom=function(){return this.calculateZoom_()},a.AnimatedPreviewController.prototype.getCoordinates=function(a,b){var c=this.container.offset();a-=c.left,b-=c.top;var d=this.getZoom();return{x:Math.floor(a/d),y:Math.floor(b/d)}},a.AnimatedPreviewController.prototype.onFPSSliderChange=function(){this.setFPS(parseInt($("#preview-fps")[0].value,10))},a.AnimatedPreviewController.prototype.setFPS=function(a){a&&(this.fps=a,$("#preview-fps").val(this.fps),$("#display-fps").html(this.fps+" FPS"))},a.AnimatedPreviewController.prototype.getFPS=function(){return this.fps},a.AnimatedPreviewController.prototype.render=function(a){this.elapsedTime+=a;var b=Math.floor(this.elapsedTime/(1e3/this.fps));if(b!=this.currentIndex){this.currentIndex=b,this.piskelController.hasFrameAt(this.currentIndex)||(this.currentIndex=0,this.elapsedTime=0);var c=this.piskelController.getFrameAt(this.currentIndex);this.renderer.render(c)}},a.AnimatedPreviewController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame(),b=200,c=b/a.getHeight(),d=b/a.getWidth();return Math.min(c,d)},a.AnimatedPreviewController.prototype.onFrameSizeChange_=function(){this.updateZoom_(),this.updateContainerDimensions_()},a.AnimatedPreviewController.prototype.updateContainerDimensions_=function(){var a,c,d=this.container.get(0),e=pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);if(e)a=b,c=b;else{var f=this.getZoom(),g=this.piskelController.getCurrentFrame();a=g.getHeight()*f,c=g.getWidth()*f}d.style.height=a+"px",d.style.width=c+"px",d.style.marginTop=(b-a)/2+"px",d.style.marginBottom=(b-a)/2+"px",d.style.marginLeft=(b-c)/2+"px",d.style.marginRight=(b-c)/2+"px"},a.AnimatedPreviewController.prototype.toggleOnionSkin_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN,!a)}}(),function(){var a=$.namespace("pskl.controller");a.MinimapController=function(a,b,c,d){this.piskelController=a,this.animationController=b,this.drawingController=c,this.container=d,this.isClicked=!1},a.MinimapController.prototype.init=function(){this.cropFrame=document.createElement("DIV"),this.cropFrame.className="minimap-crop-frame",this.cropFrame.style.display="none",$(this.container).append(this.cropFrame),$(this.container).mousedown(this.onMinimapMousedown_.bind(this)),$("body").mousemove(this.onMinimapMousemove_.bind(this)),$("body").mouseup(this.onMinimapMouseup_.bind(this)),$.subscribe(Events.ZOOM_CHANGED,$.proxy(this.renderMinimap_,this))},a.MinimapController.prototype.renderMinimap_=function(){var a=this.getDrawingAreaZoomRatio_();a>1?this.displayCropFrame_(a,this.drawingController.getRenderer().getOffset()):this.hideCropFrame_()},a.MinimapController.prototype.displayCropFrame_=function(a,b){this.cropFrame.style.display="block",this.cropFrame.style.top=b.y*this.animationController.getZoom()+"px",this.cropFrame.style.left=b.x*this.animationController.getZoom()+"px";var c=this.getDrawingAreaZoomRatio_();this.cropFrame.style.width=this.container.width()/c+"px",this.cropFrame.style.height=this.container.height()/c+"px"},a.MinimapController.prototype.hideCropFrame_=function(){this.cropFrame.style.display="none"},a.MinimapController.prototype.onMinimapMousemove_=function(a){if(this.isClicked&&this.getDrawingAreaZoomRatio_()>1){var b=this.getCoordinatesCenteredAround_(a.clientX,a.clientY);this.drawingController.setOffset(b.x,b.y)}},a.MinimapController.prototype.onMinimapMousedown_=function(){this.isClicked=!0},a.MinimapController.prototype.onMinimapMouseup_=function(){this.isClicked=!1},a.MinimapController.prototype.getCoordinatesCenteredAround_=function(a,b){var c=this.animationController.getCoordinates(a,b),d=this.getDrawingAreaZoomRatio_(),e=this.piskelController.getCurrentFrame().getWidth(),f=this.piskelController.getCurrentFrame().getHeight(),g=e/d,h=f/d;return{x:c.x-g/2,y:c.y-h/2}},a.MinimapController.prototype.getDrawingAreaZoomRatio_=function(){var a=this.drawingController.getRenderer().getZoom(),b=this.piskelController.getCurrentFrame().getHeight()*a,c=b/this.drawingController.getRenderer().getDisplaySize().height;return c}}(),function(){var a=$.namespace("pskl.controller");a.ToolController=function(){var a=function(a,b,c){return{id:a,shortcut:b,instance:c}};this.tools=[a("simplePen","P",new pskl.drawingtools.SimplePen),a("verticalMirrorPen","V",new pskl.drawingtools.VerticalMirrorPen),a("paintBucket","B",new pskl.drawingtools.PaintBucket),a("colorSwap","A",new pskl.drawingtools.ColorSwap),a("eraser","E",new pskl.drawingtools.Eraser),a("stroke","L",new pskl.drawingtools.Stroke),a("rectangle","R",new pskl.drawingtools.Rectangle),a("circle","C",new pskl.drawingtools.Circle),a("move","M",new pskl.drawingtools.Move),a("rectangleSelect","S",new pskl.drawingtools.RectangleSelect),a("shapeSelect","Z",new pskl.drawingtools.ShapeSelect),a("lighten","U",new pskl.drawingtools.Lighten),a("colorPicker","O",new pskl.drawingtools.ColorPicker)],this.currentSelectedTool=this.tools[0],this.previousSelectedTool=this.tools[0]},a.ToolController.prototype.init=function(){this.createToolsDom_(),this.addKeyboardShortcuts_(),this.selectTool_(this.tools[0]),$("#tool-section").mousedown($.proxy(this.onToolIconClicked_,this)),$.subscribe(Events.SELECT_TOOL,this.onSelectToolEvent_.bind(this))},a.ToolController.prototype.activateToolOnStage_=function(a){var b=$("body"),c=b.data("selected-tool-class");c&&(b.removeClass(c),b.removeClass(pskl.drawingtools.Move.TOOL_ID)),b.addClass(a.instance.toolId),b.data("selected-tool-class",a.instance.toolId)},a.ToolController.prototype.onSelectToolEvent_=function(a,b){var c=this.getToolById_(b);c&&this.selectTool_(c)},a.ToolController.prototype.selectTool_=function(a){this.currentSelectedTool=a,this.activateToolOnStage_(this.currentSelectedTool);var b=$("#tool-section .tool-icon.selected"),c=$("[data-tool-id="+a.instance.toolId+"]");b.removeClass("selected"),c.addClass("selected"),$.publish(Events.TOOL_SELECTED,[a.instance])},a.ToolController.prototype.onToolIconClicked_=function(a){var b=$(a.target),c=b.closest(".tool-icon");if(c.length){var d=c.data().toolId,e=this.getToolById_(d);e&&this.selectTool_(e)}},a.ToolController.prototype.onKeyboardShortcut_=function(a){for(var b=0;b{{name}}',a)}).join("");this.colorPaletteSelect_.innerHTML=b},a.PalettesListController.prototype.fillColorListContainer=function(){var a=this.getSelectedPaletteColors_(),b=a.map(function(a){return pskl.utils.Template.replace(this.paletteColorTemplate_,{color:a})}.bind(this)).join("");this.colorListContainer_.innerHTML=b,this.highlightSelectedColors();var c=a.length>e;c&&!pskl.utils.UserAgent.isChrome?this.colorListContainer_.classList.add(d):this.colorListContainer_.classList.remove(d)},a.PalettesListController.prototype.getSelectedPaletteColors_=function(){var a=[],b=this.colorPaletteSelect_.value;if(b===Constants.CURRENT_COLORS_PALETTE_ID)a=this.usedColorService.getCurrentColors();else{var c=this.paletteService.getPaletteById(b);c&&(a=c.colors)}return a.length>Constants.MAX_CURRENT_COLORS_DISPLAYED&&(a=a.slice(0,Constants.MAX_CURRENT_COLORS_DISPLAYED)),a},a.PalettesListController.prototype.selectPaletteFromUserSettings=function(){this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE))},a.PalettesListController.prototype.selectPalette=function(a){this.colorPaletteSelect_.value=a},a.PalettesListController.prototype.onPaletteSelected_=function(){var a=this.colorPaletteSelect_.value;pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE,a),this.fillColorListContainer()},a.PalettesListController.prototype.onCreatePaletteClick_=function(){$.publish(Events.DIALOG_DISPLAY,"create-palette")},a.PalettesListController.prototype.onPaletteActionsClick_=function(a){var b=a.target.classList;b.contains("palette-action-edit")?this.editSelectedPalette_():b.contains("palette-action-delete")?this.deleteSelectedPalette_():b.contains("palette-action-download")&&this.downloadSelectedPalette_()},a.PalettesListController.prototype.editSelectedPalette_=function(){var a=this.colorPaletteSelect_.value;$.publish(Events.DIALOG_DISPLAY,{dialogId:"create-palette",initArgs:a})},a.PalettesListController.prototype.deleteSelectedPalette_=function(){var a=this.colorPaletteSelect_.value,b=this.paletteService.getPaletteById(a);window.confirm("Are you sure you want to delete palette "+b.name)&&(this.paletteService.deletePaletteById(b.id),this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID))},a.PalettesListController.prototype.downloadSelectedPalette_=function(){window.alert("not implemented yet")},a.PalettesListController.prototype.onColorContainerContextMenu=function(a){a.preventDefault()},a.PalettesListController.prototype.onColorContainerMouseup=function(a){var b=a.target,c=b.dataset.color;c&&(a.button==Constants.LEFT_BUTTON?$.publish(Events.SELECT_PRIMARY_COLOR,[c]):a.button==Constants.RIGHT_BUTTON&&$.publish(Events.SELECT_SECONDARY_COLOR,[c]))},a.PalettesListController.prototype.highlightSelectedColors=function(){this.removeClass_(b),this.removeClass_(c);var a=this.getColorContainer_(this.paletteController.getSecondaryColor());a&&(a.classList.remove(b),a.classList.add(c)),a=this.getColorContainer_(this.paletteController.getPrimaryColor()),a&&(a.classList.remove(c),a.classList.add(b))},a.PalettesListController.prototype.getColorContainer_=function(a){return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+a+'"]')},a.PalettesListController.prototype.removeClass_=function(a){var b=document.querySelector("."+a);b&&b.classList.remove(a)},a.PalettesListController.prototype.onPaletteListUpdated=function(){this.fillPaletteList(),this.selectPaletteFromUserSettings(),this.fillColorListContainer()}}(),function(){var a=$.namespace("pskl.controller");a.NotificationController=function(){},a.NotificationController.prototype.init=function(){$.subscribe(Events.SHOW_NOTIFICATION,$.proxy(this.displayMessage_,this)),$.subscribe(Events.HIDE_NOTIFICATION,$.proxy(this.removeMessage_,this))},a.NotificationController.prototype.displayMessage_=function(a,b){this.removeMessage_();var c=document.createElement("div");c.id="user-message",c.className="user-message",c.innerHTML=b.content,c.innerHTML=c.innerHTML+"
        x
        ",document.body.appendChild(c),$(c).find(".close").click($.proxy(this.removeMessage_,this)),b.behavior&&b.behavior(c)},a.NotificationController.prototype.removeMessage_=function(){var a=$("#user-message");a.length&&a.remove()}}(),function(){var a=$.namespace("pskl.controller");a.CanvasBackgroundController=function(){this.body=document.body},a.CanvasBackgroundController.prototype.init=function(){$.subscribe(Events.USER_SETTINGS_CHANGED,this.onUserSettingsChange_.bind(this)),this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND))},a.CanvasBackgroundController.prototype.onUserSettingsChange_=function(a,b,c){b==pskl.UserSettings.CANVAS_BACKGROUND&&this.updateBackgroundClass_(c)},a.CanvasBackgroundController.prototype.updateBackgroundClass_=function(a){var b=this.body.dataset.currentBackgroundClass;b&&this.body.classList.remove(b),this.body.classList.add(a),this.body.dataset.currentBackgroundClass=a}}(),function(){var a=$.namespace("pskl.controller.settings");a.ApplicationSettingsController=function(){},a.ApplicationSettingsController.prototype.init=function(){var a=pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND);$("#background-picker-wrapper").find(".background-picker[data-background-class="+a+"]").addClass("selected");var b=pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH);$("#grid-width").val(b),$("#grid-width").change(this.onGridWidthChange.bind(this)),$("#background-picker-wrapper").click(this.onBackgroundClick.bind(this))},a.ApplicationSettingsController.prototype.onGridWidthChange=function(){var a=$("#grid-width").val();pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH,parseInt(a,10))},a.ApplicationSettingsController.prototype.onBackgroundClick=function(a){var b=$(a.target).closest(".background-picker");if(b.length){var c=b.data("background-class");pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND,c),$(".background-picker").removeClass("selected"),b.addClass("selected")}}}(),function(){var a=$.namespace("pskl.controller.settings");a.ResizeController=function(a){this.piskelController=a},a.ResizeController.prototype.init=function(){this.resizeWidth=$("[name=resize-width]"),this.resizeHeight=$("[name=resize-height]"),this.resizeWidth.val(this.piskelController.getWidth()),this.resizeHeight.val(this.piskelController.getHeight()),this.cancelButton=$(".resize-cancel-button"),this.cancelButton.click(this.onCancelButtonClicked_.bind(this)),this.resizeForm=$("[name=resize-form]"),this.resizeForm.submit(this.onResizeFormSubmit_.bind(this)),this.resizeContentCheckbox=$(".resize-content-checkbox")},a.ResizeController.prototype.onResizeFormSubmit_=function(a){a.originalEvent.preventDefault();var b=(parseInt(this.resizeWidth.val(),10),parseInt(this.resizeHeight.val(),10),this.isResizeContentEnabled_(),this.piskelController.getLayers().map(this.resizeLayer_.bind(this))),c=pskl.model.Piskel.fromLayers(b,this.piskelController.getPiskel().getDescriptor());pskl.app.piskelController.setPiskel(c,!0),$.publish(Events.CLOSE_SETTINGS_DRAWER)},a.ResizeController.prototype.resizeLayer_=function(a){var b=a.getFrames().map(this.resizeFrame_.bind(this));return pskl.model.Layer.fromFrames(a.getName(),b)},a.ResizeController.prototype.resizeFrame_=function(a){var b,c=parseInt(this.resizeWidth.val(),10),d=parseInt(this.resizeHeight.val(),10);return this.isResizeContentEnabled_()?b=pskl.utils.FrameUtils.resize(a,c,d,!1):(b=new pskl.model.Frame(c,d),a.forEachPixel(function(a,c,d){c=f;f++)a.GifExportController.RESOLUTIONS.push({zoom:f});a.GifExportController.prototype.init=function(){this.optionTemplate_=pskl.utils.Template.get("gif-export-option-template"),this.uploadStatusContainerEl=document.querySelector(".gif-upload-status"),this.previewContainerEl=document.querySelector(".gif-export-preview"),this.selectResolutionEl=document.querySelector(".gif-export-select-resolution"),this.uploadButton=$(".gif-upload-button"),this.uploadButton.click(this.onUploadButtonClick_.bind(this)),this.downloadButton=$(".gif-download-button"),this.downloadButton.click(this.onDownloadButtonClick_.bind(this)),this.exportProgressStatusEl=document.querySelector(".gif-export-progress-status"),this.exportProgressBarEl=document.querySelector(".gif-export-progress-bar"),this.createOptionElements_()},a.GifExportController.prototype.onUploadButtonClick_=function(a){a.originalEvent.preventDefault();var b=this.getSelectedZoom_(),c=this.piskelController.getFPS();this.renderAsImageDataAnimatedGIF(b,c,this.onGifRenderingCompleted_.bind(this))},a.GifExportController.prototype.onDownloadButtonClick_=function(){var a=this.piskelController.getPiskel().getDescriptor().name+".gif",b=this.getSelectedZoom_(),c=this.piskelController.getFPS();this.renderAsImageDataAnimatedGIF(b,c,function(b){pskl.utils.BlobUtils.dataToBlob(b,"image/gif",function(b){pskl.utils.FileUtils.downloadAsFile(b,a)})}.bind(this))},a.GifExportController.prototype.onGifRenderingCompleted_=function(a){this.updatePreview_(a),this.previewContainerEl.classList.add("preview-upload-ongoing"),pskl.app.imageUploadService.upload(a,this.onImageUploadCompleted_.bind(this))},a.GifExportController.prototype.onImageUploadCompleted_=function(a){this.updatePreview_(a),this.updateStatus_(a),this.previewContainerEl.classList.remove("preview-upload-ongoing") -},a.GifExportController.prototype.updatePreview_=function(a){this.previewContainerEl.innerHTML="
        "},a.GifExportController.prototype.getSelectedZoom_=function(){return this.selectResolutionEl.value},a.GifExportController.prototype.createOptionElements_=function(){for(var b=a.GifExportController.RESOLUTIONS,c=0;ce,g=new window.GIF({workers:2,quality:1,width:this.piskelController.getWidth()*a,height:this.piskelController.getHeight()*a,preserveColors:f}),h=0;hb){var d=Math.round((b-c.length)/2),e=a.substring(0,d),f=a.substring(a.length-d,a.length);a=e+c+f}return a}}(),function(){var a=$.namespace("pskl.controller.settings"),b=60;a.PngExportController=function(a){this.piskelController=a},a.PngExportController.prototype.init=function(){this.previewContainerEl=document.querySelector(".png-export-preview"),this.pngFilePrefixInput=document.getElementById("zip-prefix-name"),this.pngFilePrefixInput.value="sprite_",document.querySelector(".png-download-button").addEventListener("click",this.onPngDownloadButtonClick_.bind(this)),document.querySelector(".zip-generate-button").addEventListener("click",this.onZipButtonClick_.bind(this)),this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png"))},a.PngExportController.prototype.onPngDownloadButtonClick_=function(){var a=this.getPiskelName_()+".png";pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(),function(b){pskl.utils.FileUtils.downloadAsFile(b,a)})},a.PngExportController.prototype.onZipButtonClick_=function(){for(var a=new window.JSZip,b=0;b"},a.PngExportController.prototype.shorten_=function(a,b,c){return a.length>b&&(a=a.substring(0,b),a+=c),a}}(),function(){var a=$.namespace("pskl.controller.settings");a.SaveController=function(a){this.piskelController=a},a.SaveController.prototype.init=function(){this.piskelName=document.querySelector(".piskel-name"),this.saveOnlineStatus=$("#save-online-status"),this.saveFileStatus=$("#save-file-status"),this.timestamp=new Date;var a=this.piskelController.getPiskel().getDescriptor();this.descriptionInput=$("#save-description"),this.descriptionInput.val(a.description),this.isPublicCheckbox=$("input[name=save-public-checkbox]"),this.isPublicCheckbox.prop("checked",a.isPublic),this.saveFileButton=$("#save-file-button"),this.saveFileButton.click(this.saveFile_.bind(this)),this.saveLocalButton=$("#save-browser-button"),this.saveLocalButton.click(this.saveLocal_.bind(this)),this.saveOnlineButton=$("#save-online-button"),this.saveOnlineButton.click(this.saveOnline_.bind(this)),this.saveForm=$("form[name=save-form]"),this.saveForm.submit(this.onSaveFormSubmit_.bind(this)),this.nameInput=$("#save-name"),this.nameInput.val(a.name),this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this)),pskl.app.isLoggedIn()?this.saveOnlineStatus.html(pskl.utils.Template.get("save-online-status-partial")):(this.saveOnlineButton.hide(),$(".save-public-section").hide(),this.saveOnlineStatus.html(pskl.utils.Template.get("save-please-login-partial"))),this.updateLocalStatusFilename_()},a.SaveController.prototype.updateLocalStatusFilename_=function(){this.saveFileStatus.html(pskl.utils.Template.getAndReplace("save-file-status-template",{name:this.getLocalFilename_()}))},a.SaveController.prototype.getLocalFilename_=function(){var a=this.getName(),b=pskl.utils.DateUtils.format(this.timestamp,"{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}");return a+"-"+b+".piskel"},a.SaveController.prototype.onSaveFormSubmit_=function(a){a.preventDefault(),a.stopPropagation(),pskl.app.isLoggedIn()?this.saveOnline_():this.saveLocal_()},a.SaveController.prototype.saveOnline_=function(){var a=this.getName();if(a||(a=window.prompt("Please specify a name","New piskel")),a){var b=this.getDescription(),c=!!this.isPublicCheckbox.prop("checked"),d=new pskl.model.piskel.Descriptor(a,b,c);this.piskelController.getPiskel().setDescriptor(d),this.beforeSaving_(),this.saveOnlineButton.attr("disabled",!0),this.saveOnlineStatus.html("Saving ..."),pskl.app.storageService.store({success:this.onSaveSuccess_.bind(this),error:this.onSaveError_.bind(this),after:this.afterOnlineSaving_.bind(this)})}},a.SaveController.prototype.saveLocal_=function(){var a=pskl.app.localStorageService,b=!0,c=this.getName(),d=this.getDescription();a.getPiskel(c)&&(b=window.confirm("There is already a piskel saved as "+c+". Override ?")),b&&(this.beforeSaving_(),a.save(c,d,pskl.app.piskelController.serialize()),window.setTimeout(function(){this.onSaveSuccess_(),this.afterSaving_()}.bind(this),500))},a.SaveController.prototype.saveFile_=function(){this.beforeSaving_(),pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(),function(a){pskl.utils.FileUtils.downloadAsFile(a,this.getLocalFilename_()),this.onSaveSuccess_(),this.afterSaving_()}.bind(this),"application/piskel+json")},a.SaveController.prototype.getName=function(){return this.nameInput.val()},a.SaveController.prototype.getDescription=function(){return this.descriptionInput.val()},a.SaveController.prototype.beforeSaving_=function(){this.updatePiskelDescriptor_(),this.piskelName&&this.piskelName.classList.add("piskel-name-saving")},a.SaveController.prototype.updatePiskelDescriptor_=function(){var a=this.getName(),b=this.getDescription(),c=!!this.isPublicCheckbox.prop("checked"),d=new pskl.model.piskel.Descriptor(a,b,c);this.piskelController.getPiskel().setDescriptor(d)},a.SaveController.prototype.onSaveSuccess_=function(){$.publish(Events.CLOSE_SETTINGS_DRAWER),$.publish(Events.SHOW_NOTIFICATION,[{content:"Successfully saved !"}]),$.publish(Events.PISKEL_SAVED)},a.SaveController.prototype.onSaveError_=function(a){$.publish(Events.SHOW_NOTIFICATION,[{content:"Saving failed ("+a+")"}])},a.SaveController.prototype.afterOnlineSaving_=function(){this.saveOnlineButton.attr("disabled",!1),this.saveOnlineStatus.html(""),this.afterSaving_()},a.SaveController.prototype.afterSaving_=function(){this.piskelName&&this.piskelName.classList.remove("piskel-name-saving"),window.setTimeout($.publish.bind($,Events.HIDE_NOTIFICATION),5e3)}}(),function(){var a=$.namespace("pskl.controller.settings");a.ImportController=function(a){this.piskelController=a,this.importedImage_=null},a.ImportController.prototype.init=function(){this.browseLocalButton=document.querySelector(".browse-local-button"),this.browseLocalButton.addEventListener("click",this.onBrowseLocalClick_.bind(this)),this.hiddenFileInput=$("[name=file-upload-input]"),this.hiddenFileInput.change(this.onFileUploadChange_.bind(this)),this.fileInputButton=$(".file-input-button"),this.fileInputButton.click(this.onFileInputClick_.bind(this)),this.hiddenOpenPiskelInput=$("[name=open-piskel-input]"),this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this)),this.openPiskelInputButton=$(".open-piskel-button"),this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this)),this.prevSessionContainer=$(".previous-session"),this.previousSessionTemplate_=pskl.utils.Template.get("previous-session-info-template"),this.fillRestoreSession_()},a.ImportController.prototype.closeDrawer_=function(){$.publish(Events.CLOSE_SETTINGS_DRAWER)},a.ImportController.prototype.onFileUploadChange_=function(){this.importPictureFromFile_()},a.ImportController.prototype.onFileInputClick_=function(){this.hiddenFileInput.click()},a.ImportController.prototype.onOpenPiskelChange_=function(){var a=this.hiddenOpenPiskelInput.get(0).files;1==a.length&&this.openPiskelFile_(a[0])},a.ImportController.prototype.onOpenPiskelClick_=function(){this.hiddenOpenPiskelInput.click()},a.ImportController.prototype.onBrowseLocalClick_=function(){$.publish(Events.DIALOG_DISPLAY,"browse-local"),this.closeDrawer_()},a.ImportController.prototype.openPiskelFile_=function(a){this.isPiskel_(a)&&(pskl.utils.PiskelFileUtils.loadFromFile(a,function(a,b,c){a.setDescriptor(b),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(c)}),this.closeDrawer_())},a.ImportController.prototype.importPictureFromFile_=function(){var a=this.hiddenFileInput.get(0).files;if(1==a.length){var b=a[0];if(!this.isImage_(b))throw this.closeDrawer_(),"File is not an image : "+b.type;$.publish(Events.DIALOG_DISPLAY,{dialogId:"import-image",initArgs:b}),this.closeDrawer_()}},a.ImportController.prototype.isImage_=function(a){return 0===a.type.indexOf("image")},a.ImportController.prototype.isPiskel_=function(a){return/\.piskel$/.test(a.name)},a.ImportController.prototype.fillRestoreSession_=function(){var a=pskl.app.backupService.getPreviousPiskelInfo();if(a){var b={name:a.name,date:pskl.utils.DateUtils.format(a.date,"{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}")};this.prevSessionContainer.html(pskl.utils.Template.replace(this.previousSessionTemplate_,b)),$(".restore-session-button").click(this.onRestorePreviousSessionClick_.bind(this))}else this.prevSessionContainer.html("No piskel backup was found on this browser.")},a.ImportController.prototype.onRestorePreviousSessionClick_=function(){window.confirm("This will erase your current workspace. Continue ?")&&(pskl.app.backupService.load(),$.publish(Events.CLOSE_SETTINGS_DRAWER))}}(),function(){var a=$.namespace("pskl.controller.settings"),b={user:{template:"templates/settings/application.html",controller:a.ApplicationSettingsController},resize:{template:"templates/settings/resize.html",controller:a.ResizeController},"export":{template:"templates/settings/export.html",controller:a.ImageExportController},"import":{template:"templates/settings/import.html",controller:a.ImportController},localstorage:{template:"templates/settings/localstorage.html",controller:a.LocalStorageController},save:{template:"templates/settings/save.html",controller:a.SaveController}},c="has-expanded-drawer",d="expanded";a.SettingsController=function(a){this.piskelController=a,this.drawerContainer=document.getElementById("drawer-container"),this.settingsContainer=$("[data-pskl-controller=settings]"),this.isExpanded=!1,this.currentSetting=null},a.SettingsController.prototype.init=function(){$("[data-setting]").click(this.onSettingIconClick.bind(this)),$("body").click(this.onBodyClick.bind(this)),$.subscribe(Events.CLOSE_SETTINGS_DRAWER,this.closeDrawer.bind(this))},a.SettingsController.prototype.onSettingIconClick=function(a){var b=a.originalEvent.currentTarget,c=b.getAttribute("data-setting");this.currentSetting!=c?this.loadSetting(c):this.closeDrawer(),a.originalEvent.stopPropagation(),a.originalEvent.preventDefault()},a.SettingsController.prototype.onBodyClick=function(a){var b=a.target,c=pskl.utils.Dom.isParent(b,this.drawerContainer),d=b.getAttribute("data-setting"),e=c||d;this.isExpanded&&!e&&this.closeDrawer()},a.SettingsController.prototype.loadSetting=function(a){this.drawerContainer.innerHTML=pskl.utils.Template.get(b[a].template),new b[a].controller(this.piskelController).init(),this.settingsContainer.addClass(d),$("."+c).removeClass(c),$("[data-setting="+a+"]").addClass(c),this.isExpanded=!0,this.currentSetting=a},a.SettingsController.prototype.closeDrawer=function(){this.settingsContainer.removeClass(d),$("."+c).removeClass(c),this.isExpanded=!1,this.currentSetting=null,document.activeElement.blur()}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.AbstractDialogController=function(){},a.AbstractDialogController.prototype.init=function(){this.closeButton=document.querySelector(".dialog-close"),this.closeButton.addEventListener("click",this.closeDialog.bind(this))},a.AbstractDialogController.prototype.destroy=function(){},a.AbstractDialogController.prototype.closeDialog=function(){this.destroy(),$.publish(Events.DIALOG_HIDE)}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.CreatePaletteController=function(){this.paletteService=pskl.app.paletteService,this.paletteImportService=pskl.app.paletteImportService,this.selectedIndex=-1},pskl.utils.inherit(a.CreatePaletteController,a.AbstractDialogController),a.CreatePaletteController.prototype.init=function(a){this.superclass.init.call(this),this.colorsList=document.querySelector(".colors-list"),this.colorPreviewEl=document.querySelector(".color-preview"),this.hiddenFileInput=document.querySelector(".create-palette-import-input"),this.nameInput=document.querySelector('input[name="palette-name"]');var b=document.querySelector(".create-palette-submit"),c=document.querySelector(".create-palette-cancel"),d=document.querySelector(".create-palette-import-button");this.colorsList.addEventListener("click",this.onColorContainerClick_.bind(this)),this.nameInput.addEventListener("input",this.onNameInputChange_.bind(this)),this.hiddenFileInput.addEventListener("change",this.onFileInputChange_.bind(this)),b.addEventListener("click",this.onSubmitButtonClick_.bind(this)),c.addEventListener("click",this.closeDialog.bind(this)),d.addEventListener("click",this.onImportFileButtonClick_.bind(this));var e=document.querySelector(".color-picker-container");this.hslRgbColorPicker=new pskl.controller.widgets.HslRgbColorPicker(e,this.onColorUpdated_.bind(this)),this.hslRgbColorPicker.init();var f;if(a){var g=this.paletteService.getPaletteById(a);f=pskl.model.Palette.fromObject(g)}else f=new pskl.model.Palette(pskl.utils.Uuid.generate(),"New palette",[]);this.setPalette_(f)},a.CreatePaletteController.prototype.setPalette_=function(a){this.palette=a,this.nameInput.value=pskl.utils.unescapeHtml(this.palette.name),this.refresh_()},a.CreatePaletteController.prototype.destroy=function(){this.colorsList=null,this.colorPreviewEl=null,this.nameInput=null},a.CreatePaletteController.prototype.onColorUpdated_=function(a){var b=a.toRgbString();this.colorPreviewEl.style.background=b,this.palette&&(this.palette.set(this.selectedIndex,b),this.refreshColorElement_(this.selectedIndex))},a.CreatePaletteController.prototype.refreshColorElement_=function(a){var b=this.palette.get(this.selectedIndex),c=document.querySelector('[data-palette-index="'+a+'"]');c&&(c.style.background=b,c.classList.toggle("light-color",this.isLight_(b)))},a.CreatePaletteController.prototype.onColorContainerClick_=function(a){var b=a.target;b.classList.contains("create-palette-color")?this.onPaletteColorClick_(a,b):b.classList.contains("create-palette-new-color")?this.onNewColorClick_(a,b):b.classList.contains("create-palette-remove-color")&&this.onRemoveColorClick_(a,b),this.refresh_()},a.CreatePaletteController.prototype.onPaletteColorClick_=function(a,b){var c=parseInt(b.dataset.paletteIndex,10);this.selectColor_(c)},a.CreatePaletteController.prototype.onRemoveColorClick_=function(a,b){var c=b.parentNode,d=parseInt(c.dataset.paletteIndex,10);this.removeColor_(d)},a.CreatePaletteController.prototype.onNewColorClick_=function(){var a=this.palette.get(this.selectedIndex)||"#000000";this.palette.add(a),this.selectColor_(this.palette.size()-1)},a.CreatePaletteController.prototype.onSubmitButtonClick_=function(){this.paletteService.savePalette(this.palette),this.closeDialog()},a.CreatePaletteController.prototype.onImportFileButtonClick_=function(){this.hiddenFileInput.click()},a.CreatePaletteController.prototype.onFileInputChange_=function(){var a=this.hiddenFileInput.files;1==a.length&&this.paletteImportService.read(a[0],this.setPalette_.bind(this))},a.CreatePaletteController.prototype.onNameInputChange_=function(){this.palette.name=pskl.utils.escapeHtml(this.nameInput.value)},a.CreatePaletteController.prototype.selectColor_=function(a){this.selectedIndex=a,this.hslRgbColorPicker.setColor(this.palette.get(a))},a.CreatePaletteController.prototype.removeColor_=function(a){this.palette.removeAt(a),this.refresh_()},a.CreatePaletteController.prototype.refresh_=function(){var a="",b=pskl.utils.Template.get("create-palette-color-template"),c=this.palette.colors;c.forEach(function(c,d){var e=d===this.selectedIndex;a+=pskl.utils.Template.replace(b,{color:c,index:d,":selected":e,":light-color":this.isLight_(c)})}.bind(this)),a+='
      • +
      • ',this.colorsList.innerHTML=a,$(".colors-list").sortable({placeholder:"colors-list-drop-proxy",update:this.onDrop_.bind(this),items:".create-palette-color"})},a.CreatePaletteController.prototype.isLight_=function(a){var b=window.tinycolor(a).toRgb();return b.r+b.b+b.g>384},a.CreatePaletteController.prototype.onDrop_=function(a,b){var c=b.item.get(0),d=parseInt(c.dataset.paletteIndex,10),e=$(".create-palette-color").index(b.item);this.palette.move(d,e),this.selectedIndex=e,this.refresh_()}}(),function(){var a=$.namespace("pskl.controller.dialogs"),b=60;a.ImportImageController=function(){this.importedImage_=null,this.file_=null},pskl.utils.inherit(a.ImportImageController,a.AbstractDialogController),a.ImportImageController.prototype.init=function(a){this.superclass.init.call(this),this.file_=a,this.importPreview=$(".import-section-preview"),this.fileNameContainer=$(".import-image-file-name"),this.resizeWidth=$("[name=resize-width]"),this.resizeHeight=$("[name=resize-height]"),this.smoothResize=$("[name=smooth-resize-checkbox]"),this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this,"width")),this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this,"height")),this.importImageForm=$("[name=import-image-form]"),this.importImageForm.submit(this.onImportFormSubmit_.bind(this)),pskl.utils.FileUtils.readImageFile(this.file_,this.onImageLoaded_.bind(this))},a.ImportImageController.prototype.onImportFormSubmit_=function(a){a.originalEvent.preventDefault(),this.importImageToPiskel_()},a.ImportImageController.prototype.onResizeInputKeyUp_=function(a,b){this.importedImage_&&this.synchronizeResizeFields_(b.target.value,a)},a.ImportImageController.prototype.synchronizeResizeFields_=function(a,b){a=parseInt(a,10),isNaN(a)&&(a=0);var c=this.importedImage_.height,d=this.importedImage_.width;"width"===b?this.resizeHeight.val(Math.round(a*c/d)):this.resizeWidth.val(Math.round(a*d/c))},a.ImportImageController.prototype.onImageLoaded_=function(a){this.importedImage_=a;var b=this.importedImage_.width,c=this.importedImage_.height;this.importedImage_.onload=function(){};var d=this.extractFileNameFromPath_(this.file_.name);this.fileNameContainer.html(d),this.resizeWidth.val(b),this.resizeHeight.val(c),this.importPreview.width("auto"),this.importPreview.html(""),this.importPreview.append(this.createImagePreview_())},a.ImportImageController.prototype.createImagePreview_=function(){var a=document.createElement("IMG");return a.src=this.importedImage_.src,a.setAttribute("height",b),a},a.ImportImageController.prototype.extractFileNameFromPath_=function(a){var b=[];return b=-1!==a.indexOf("/")?a.split("/"):-1!==a.indexOf("\\")?a.split("\\"):[a],b[b.length-1]},a.ImportImageController.prototype.importImageToPiskel_=function(){var a=this.importedImage_;if(a&&window.confirm("You are about to create a new Piskel, unsaved changes will be lost.")){var b=new window.SuperGif({gif:a});b.load({success:function(){var a=b.getFrames().map(function(a){return pskl.CanvasUtils.createFromImageData(a.data)});this.createPiskelFromImages_(a),this.closeDialog()}.bind(this),error:function(){this.createPiskelFromImages_([a]),this.closeDialog()}.bind(this)})}},a.ImportImageController.prototype.createFramesFromImages_=function(a){var b=this.resizeWidth.val(),c=this.resizeHeight.val(),d=!!this.smoothResize.prop("checked"),e=a.map(function(a){var e=pskl.utils.ImageResizer.resize(a,b,c,d);return pskl.utils.FrameUtils.createFromImage(e)});return e},a.ImportImageController.prototype.createPiskelFromImages_=function(a){var b=this.createFramesFromImages_(a),c=pskl.model.Layer.fromFrames("Layer 1",b),d=new pskl.model.piskel.Descriptor("Imported piskel",""),e=pskl.model.Piskel.fromLayers([c],d);pskl.app.piskelController.setPiskel(e),pskl.app.animationController.setFPS(Constants.DEFAULT.FPS)}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.BrowseLocalController=function(){},pskl.utils.inherit(a.BrowseLocalController,a.AbstractDialogController),a.BrowseLocalController.prototype.init=function(){this.superclass.init.call(this),this.localStorageItemTemplate_=pskl.utils.Template.get("local-storage-item-template"),this.service_=pskl.app.localStorageService,this.piskelList=$(".local-piskel-list"),this.prevSessionContainer=$(".previous-session"),this.fillLocalPiskelsList_(),this.piskelList.click(this.onPiskelsListClick_.bind(this))},a.BrowseLocalController.prototype.onPiskelsListClick_=function(a){var b=a.target.getAttribute("data-action"),c=a.target.getAttribute("data-name");"load"===b?window.confirm("This will erase your current piskel. Continue ?")&&(this.service_.load(c),this.closeDialog()):"delete"===b&&window.confirm("This will permanently DELETE this piskel from your computer. Continue ?")&&(this.service_.remove(c),this.fillLocalPiskelsList_())},a.BrowseLocalController.prototype.fillLocalPiskelsList_=function(){var a="",b=this.service_.getKeys();b.sort(function(a,b){return a.dateb.date?-1:0}),b.forEach(function(b){var c=pskl.utils.DateUtils.format(b.date,"{{Y}}/{{M}}/{{D}} {{H}}:{{m}}");a+=pskl.utils.Template.replace(this.localStorageItemTemplate_,{name:b.name,date:c})}.bind(this));var c=this.piskelList.get(0).tBodies[0];c.innerHTML=a}}(),function(){var a=$.namespace("pskl.controller.dialogs"),b={"create-palette":{template:"templates/dialogs/create-palette.html",controller:a.CreatePaletteController},"browse-local":{template:"templates/dialogs/browse-local.html",controller:a.BrowseLocalController},"import-image":{template:"templates/dialogs/import-image.html",controller:a.ImportImageController}};a.DialogsController=function(a){this.piskelController=a,this.currentDialog_=null},a.DialogsController.prototype.init=function(){this.dialogContainer_=document.getElementById("dialog-container"),this.dialogWrapper_=document.getElementById("dialog-container-wrapper"),$.subscribe(Events.DIALOG_DISPLAY,this.onDialogDisplayEvent_.bind(this)),$.subscribe(Events.DIALOG_HIDE,this.onDialogHideEvent_.bind(this)),pskl.app.shortcutService.addShortcut("alt+P",this.onDialogDisplayEvent_.bind(this,null,"create-palettes")),this.dialogWrapper_.classList.add("animated")},a.DialogsController.prototype.onDialogDisplayEvent_=function(a,c){var d,e;if("string"==typeof c?d=c:(d=c.dialogId,e=c.initArgs),!this.isDisplayed()){var f=b[d];if(f){this.dialogContainer_.classList.add(d),this.dialogContainer_.innerHTML=pskl.utils.Template.get(f.template);var g=new f.controller(this.piskelController);g.init(e),this.showDialogWrapper_(),this.currentDialog_={id:d,controller:g}}else console.error("Could not find dialog configuration for dialogId : "+d)}},a.DialogsController.prototype.onDialogHideEvent_=function(){this.hideDialog()},a.DialogsController.prototype.showDialogWrapper_=function(){pskl.app.shortcutService.addShortcut("ESC",this.hideDialog.bind(this)),this.dialogWrapper_.classList.add("show")},a.DialogsController.prototype.hideDialog=function(){var a=this.currentDialog_;if(a){a.controller.destroy();var b=this.currentDialog_.id;window.setTimeout(function(){this.dialogContainer_.classList.remove(b)}.bind(this),800)}this.hideDialogWrapper_(),this.currentDialog_=null},a.DialogsController.prototype.hideDialogWrapper_=function(){pskl.app.shortcutService.removeShortcut("ESC"),this.dialogWrapper_.classList.remove("show")},a.DialogsController.prototype.isDisplayed=function(){return null!==this.currentDialog_}}(),function(){var a=$.namespace("pskl.controller.widgets");a.HslRgbColorPicker=function(a,b){this.container=a,this.colorUpdatedCallback=b,this.lastInputTimestamp_=0},a.HslRgbColorPicker.prototype.init=function(){var a=pskl.utils.UserAgent.isChrome||pskl.utils.UserAgent.isFirefox,b=a?"input":"change";this.container.addEventListener(b,this.onPickerChange_.bind(this)),this.spectrumEl=this.container.querySelector(".color-picker-spectrum"),$(this.spectrumEl).spectrum({flat:!0,showInput:!0,showButtons:!1,move:this.setColor.bind(this),change:this.setColor.bind(this)}),this.setColor("#000000")},a.HslRgbColorPicker.prototype.onPickerChange_=function(a){var b=a.target,c=b.dataset.model,d=b.dataset.dimension,e=parseInt(b.value,10);("v"===d||"s"===d)&&(e/=100);var f;"rgb"===c?f=this.tinyColor.toRgb():"hsv"===c&&(f=this.hsvColor),isNaN(e)?e=f[d]:f[d]=e,this.setColor(f)},a.HslRgbColorPicker.prototype.setColor=function(a){this.unplugged||(this.unplugged=!0,this.hsvColor=this.toHsvColor_(a),this.tinyColor=this.toTinyColor_(a),this.updateInputs(),$(".color-picker-spectrum").spectrum("set",this.tinyColor),this.colorUpdatedCallback(this.tinyColor),this.unplugged=!1)},a.HslRgbColorPicker.prototype.updateInputs=function(){for(var a=this.container.querySelectorAll("input"),b=this.tinyColor.toRgb(),c=0;c";this.piskelController=a},a.LocalStorageService.prototype.init=function(){},a.LocalStorageService.prototype.save=function(a,b,c){this.removeFromKeys_(a),this.addToKeys_(a,b,Date.now()),window.localStorage.setItem("piskel."+a,c)},a.LocalStorageService.prototype.load=function(a){var b=this.getPiskel(a),c=(this.getKey_(a),JSON.parse(b)),d=c.piskel.fps,e=c.piskel.description;pskl.utils.serialization.Deserializer.deserialize(c,function(b){b.setDescriptor(new pskl.model.piskel.Descriptor(a,e,!0)),pskl.app.piskelController.setPiskel(b),pskl.app.animationController.setFPS(d)})},a.LocalStorageService.prototype.remove=function(a){this.removeFromKeys_(a),window.localStorage.removeItem("piskel."+a)},a.LocalStorageService.prototype.saveKeys_=function(a){window.localStorage.setItem("piskel.keys",JSON.stringify(a))},a.LocalStorageService.prototype.removeFromKeys_=function(a){var b=this.getKeys(),c=b.filter(function(b){return b.name!==a});this.saveKeys_(c)},a.LocalStorageService.prototype.getKey_=function(a){var b=this.getKeys().filter(function(b){return b.name===a});return b.length>0?b[0]:null},a.LocalStorageService.prototype.addToKeys_=function(a,b,c){var d=this.getKeys();d.push({name:a,description:b,date:c}),this.saveKeys_(d)},a.LocalStorageService.prototype.getPiskel=function(a){return window.localStorage.getItem("piskel."+a)},a.LocalStorageService.prototype.getKeys=function(){var a=window.localStorage.getItem("piskel.keys");return JSON.parse(a)||[]}}(),function(){var a=$.namespace("pskl.service");a.GithubStorageService=function(a){this.piskelController=a},a.GithubStorageService.prototype.init=function(){},a.GithubStorageService.prototype.store=function(){throw"Github save is no longer available. Use local save instead"}}(),function(){var a=$.namespace("pskl.service");a.AppEngineStorageService=function(a){this.piskelController=a},a.AppEngineStorageService.prototype.init=function(){},a.AppEngineStorageService.prototype.store=function(a){var b=this.piskelController.getPiskel(),c=b.getDescriptor(),d={framesheet:this.piskelController.serialize(),fps:this.piskelController.getFPS(),name:c.name,description:c.description,frames:this.piskelController.getFrameCount(),first_frame_as_png:pskl.app.getFirstFrameAsPng(),framesheet_as_png:pskl.app.getFramesheetAsPng()};c.isPublic&&(d["public"]=!0);var e=function(){a.success(),a.after()},f=function(b){a.error(b.status),a.after()};pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE,d,e,f)}}(),function(){var a=$.namespace("pskl.service"),b=6e4;a.BackupService=function(a){this.piskelController=a,this.lastHash=null},a.BackupService.prototype.init=function(){var a=window.localStorage.getItem("bkp.next.piskel"),c=window.localStorage.getItem("bkp.next.info");a&&c&&(window.localStorage.setItem("bkp.prev.piskel",a),window.localStorage.setItem("bkp.prev.info",c)),window.setInterval(this.backup.bind(this),b)},a.BackupService.prototype.backup=function(){var a=this.piskelController.getPiskel(),b=a.getDescriptor(),c=a.getHash(),d={name:b.name,description:b.info,fps:this.piskelController.getFPS(),date:Date.now(),hash:c}; -c!==this.lastHash&&(this.lastHash=c,window.localStorage.setItem("bkp.next.piskel",this.piskelController.serialize()),window.localStorage.setItem("bkp.next.info",JSON.stringify(d)))},a.BackupService.prototype.getPreviousPiskelInfo=function(){var a=window.localStorage.getItem("bkp.prev.info");return a?JSON.parse(a):void 0},a.BackupService.prototype.load=function(){var a=window.localStorage.getItem("bkp.prev.piskel"),b=window.localStorage.getItem("bkp.prev.info");a=JSON.parse(a),b=JSON.parse(b),pskl.utils.serialization.Deserializer.deserialize(a,function(a){a.setDescriptor(new pskl.model.piskel.Descriptor(b.name,b.description,!0)),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(b.fps)})}}(),function(){var a=$.namespace("pskl.service");a.BeforeUnloadService=function(a){this.piskelController=a},a.BeforeUnloadService.prototype.init=function(){window.addEventListener("beforeunload",this.onBeforeUnload.bind(this))},a.BeforeUnloadService.prototype.onBeforeUnload=function(a){if(pskl.app.backupService.backup(),pskl.app.savedStatusService.isDirty()){var b="Your Piskel seems to have unsaved changes";return(a||window.event).returnValue=b,b}}}(),function(){var a=$.namespace("pskl.service");a.HistoryService=function(a,b,c){this.piskelController=a||pskl.app.piskelController,this.shortcutService=b||pskl.app.shortcutService,this.deserializer=c||pskl.utils.serialization.Deserializer,this.stateQueue=[],this.currentIndex=-1,this.lastLoadState=-1,this.saveNextAsSnapshot=!1},a.HistoryService.SNAPSHOT="SNAPSHOT",a.HistoryService.REPLAY="REPLAY",a.HistoryService.SNAPSHOT_PERIOD=50,a.HistoryService.LOAD_STATE_INTERVAL=50,a.HistoryService.REPLAY_NO_SNAPSHOT="REPLAY_NO_SNAPSHOT",a.HistoryService.prototype.init=function(){$.subscribe(Events.PISKEL_SAVE_STATE,this.onSaveStateEvent.bind(this)),this.shortcutService.addShortcut("ctrl+Z",this.undo.bind(this)),this.shortcutService.addShortcut("ctrl+Y",this.redo.bind(this)),this.saveState({type:a.HistoryService.SNAPSHOT})},a.HistoryService.prototype.onSaveStateEvent=function(a,b){this.saveState(b)},a.HistoryService.prototype.saveState=function(b){this.stateQueue=this.stateQueue.slice(0,this.currentIndex+1),this.currentIndex=this.currentIndex+1;var c={action:b,frameIndex:this.piskelController.currentFrameIndex,layerIndex:this.piskelController.currentLayerIndex},d=b.type===a.HistoryService.SNAPSHOT,e=b.type===a.HistoryService.REPLAY_NO_SNAPSHOT,f=this.currentIndex%a.HistoryService.SNAPSHOT_PERIOD===0||this.saveNextAsSnapshot;e&&f?this.saveNextAsSnapshot=!0:(d||f)&&(c.piskel=this.piskelController.serialize(!0),this.saveNextAsSnapshot=!1),this.stateQueue.push(c)},a.HistoryService.prototype.undo=function(){this.loadState(this.currentIndex-1)},a.HistoryService.prototype.redo=function(){this.loadState(this.currentIndex+1)},a.HistoryService.prototype.isLoadStateAllowed_=function(b){var c=Date.now()-this.lastLoadState>a.HistoryService.LOAD_STATE_INTERVAL,d=b>=0&&bb)throw"Could not find previous SNAPSHOT saved in history stateQueue";var c=this.getSnapshotFromState_(b),d=this.onPiskelLoaded_.bind(this,a,b);this.deserializer.deserialize(c,d)}}catch(e){window.console.error("[CRITICAL ERROR] : Unable to load a history state."),"string"==typeof e?window.console.error(e):(window.console.error(e.message),window.console.error(e.stack)),this.stateQueue=[],this.currentIndex=-1}},a.HistoryService.prototype.getSnapshotFromState_=function(a){var b=this.stateQueue[a],c=b.piskel;return"string"==typeof c&&(c=JSON.parse(c),b.piskel=c),c},a.HistoryService.prototype.onPiskelLoaded_=function(a,b,c){var d=this.getPiskelSize_();c.setDescriptor(this.piskelController.piskel.getDescriptor()),this.piskelController.setPiskel(c);for(var e=b+1;a>=e;e++){var f=this.stateQueue[e];this.setupState(f),this.replayState(f)}var g=this.stateQueue[a+1];g&&this.setupState(g),this.currentIndex=a,$.publish(Events.PISKEL_RESET),d!==this.getPiskelSize_()&&$.publish(Events.FRAME_SIZE_CHANGED)},a.HistoryService.prototype.getPiskelSize_=function(){return this.piskelController.getWidth()+"x"+this.piskelController.getHeight()},a.HistoryService.prototype.setupState=function(a){this.piskelController.setCurrentFrameIndex(a.frameIndex),this.piskelController.setCurrentLayerIndex(a.layerIndex)},a.HistoryService.prototype.replayState=function(a){var b=a.action,c=(b.type,this.piskelController.getLayerAt(a.layerIndex)),d=c.getFrameAt(a.frameIndex);b.scope.replay(d,b.replay)}}(),function(){var a=$.namespace("pskl.service.palette");a.PaletteService=function(){this.palettes=[],this.localStorageService=window.localStorage},a.PaletteService.prototype.getPalettes=function(){var a=this.localStorageService.getItem("piskel.palettes");return JSON.parse(a)||[]},a.PaletteService.prototype.getPaletteById=function(a){var b=this.getPalettes();return this.findPaletteInArray_(a,b)},a.PaletteService.prototype.savePalette=function(a){var b=this.getPalettes(),c=this.findPaletteInArray_(a.id,b);if(c){var d=b.indexOf(c);b.splice(d,1,a)}else b.push(a);this.savePalettes_(b),$.publish(Events.SHOW_NOTIFICATION,[{content:"Palette "+a.name+" successfully saved !"}]),window.setTimeout($.publish.bind($,Events.HIDE_NOTIFICATION),2e3)},a.PaletteService.prototype.deletePaletteById=function(a){var b=this.getPalettes(),c=b.filter(function(b){return b.id!==a});this.savePalettes_(c)},a.PaletteService.prototype.savePalettes_=function(a){this.localStorageService.setItem("piskel.palettes",JSON.stringify(a)),$.publish(Events.PALETTE_LIST_UPDATED)},a.PaletteService.prototype.findPaletteInArray_=function(a,b){var c=null;return b.forEach(function(b){b.id===a&&(c=b)}),c}}(),function(){var a=$.namespace("pskl.service.palette"),b=["gpl"];a.PaletteImportService=function(){},a.PaletteImportService.prototype.read=function(b,c,d){var e;if(this.isImage_(b)?e=new a.PaletteImageReader(b,c,d):this.isSupportedFormat_(b)&&(e=this.getFileReader_(b,c,d)),!e)throw"Could not find reader for file : "+b.name;e.read()},a.PaletteImportService.prototype.isImage_=function(a){return 0===a.type.indexOf("image")},a.PaletteImportService.prototype.getFileReader_=function(b,c,d){var e=this.getExtension_(b);return"gpl"===e?new a.PaletteGplReader(b,c,d):void 0},a.PaletteImportService.prototype.isSupportedFormat_=function(a){var c=this.getExtension_(a);return-1!=b.indexOf(c)},a.PaletteImportService.prototype.getExtension_=function(a){var b=a.name.split(".");return b[b.length-1]}}(),function(){var a=$.namespace("pskl.service.palette"),b=/^(\d{1,3}\s+)(\d{1,3}\s+)(\d{1,3}\s+)/,c=/^name\s*\:\s*(.*)$/i;a.PaletteGplReader=function(a,b,c){this.file=a,this.onSuccess=b,this.onError=c},a.PaletteGplReader.prototype.read=function(){pskl.utils.FileUtils.readFile(this.file,this.onFileLoaded_.bind(this))},a.PaletteGplReader.prototype.onFileLoaded_=function(a){var d=pskl.utils.Base64.toText(a),e=d.match(/[^\r\n]+/g),f=e.map(function(a){var b=a.match(c);return b?b[1]:""}).join(""),g=e.filter(function(a){return b.test(a)}),h=g.map(function(a){var c=a.match(b),d=window.tinycolor({r:parseInt(c[1],10),g:parseInt(c[2],10),b:parseInt(c[3],10)});return d.toRgbString()});if(f&&h.length){var i=pskl.utils.Uuid.generate(),j=new pskl.model.Palette(i,f,h);this.onSuccess(j)}else this.onError()}}(),function(){var a=$.namespace("pskl.service.palette");a.PaletteImageReader=function(a,b,c){this.file=a,this.onSuccess=b,this.onError=c},a.PaletteImageReader.prototype.read=function(){pskl.utils.FileUtils.readImageFile(this.file,this.onImageLoaded_.bind(this))},a.PaletteImageReader.prototype.onImageLoaded_=function(a){var b=pskl.utils.FrameUtils.createFromImage(a),c={};b.forEachPixel(function(a){c[a]=!0}),delete c[Constants.TRANSPARENT_COLOR];var d=Object.keys(c),e=pskl.utils.Uuid.generate(),f=new pskl.model.Palette(e,this.file.name+" palette",d);this.onSuccess(f)}}(),function(){var a=$.namespace("pskl.service");a.SavedStatusService=function(a){this.piskelController=a},a.SavedStatusService.prototype.init=function(){$.subscribe(Events.TOOL_RELEASED,this.onToolReleased.bind(this)),$.subscribe(Events.PISKEL_RESET,this.onPiskelReset.bind(this)),$.subscribe(Events.PISKEL_SAVED,this.onPiskelSaved.bind(this))},a.SavedStatusService.prototype.onPiskelReset=function(){var a=this.piskelController.getPiskel();a.firstResetDone_?this.updateDirtyStatus(!0):a.firstResetDone_=!0},a.SavedStatusService.prototype.onToolReleased=function(){this.updateDirtyStatus(!0)},a.SavedStatusService.prototype.onPiskelSaved=function(){this.updateDirtyStatus(!1)},a.SavedStatusService.prototype.updateDirtyStatus=function(a){var b=this.piskelController.getPiskel();b.isDirty_!==a&&(b.isDirty_=a,this.updatePiskelName())},a.SavedStatusService.prototype.updatePiskelName=function(){var a=this.piskelController.getPiskel(),b=a.getDescriptor().name;$(".piskel-name").html(a.isDirty_?b+" *":b)},a.SavedStatusService.prototype.isDirty=function(){var a=this.piskelController.getPiskel();return a.isDirty_}}(),function(){var a=$.namespace("pskl.service.keyboard");a.ShortcutService=function(){this.shortcuts_={}},a.ShortcutService.prototype.init=function(){$(document.body).keydown($.proxy(this.onKeyUp_,this))},a.ShortcutService.prototype.addShortcut=function(a,b){var c=this.parseKey_(a.toLowerCase()),d=c.key,e=c.meta;if(this.shortcuts_[d]=this.shortcuts_[d]||{},this.shortcuts_[d][e]){var f=("normal"!==e?e+" + ":"")+d;console.error("[ShortcutService] >>> Shortcut ["+f+"] already registered")}else this.shortcuts_[d][e]=b},a.ShortcutService.prototype.removeShortcut=function(a){var b=this.parseKey_(a.toLowerCase()),c=b.key,d=b.meta;this.shortcuts_[c]=this.shortcuts_[c]||{},this.shortcuts_[c][d]=null},a.ShortcutService.prototype.parseKey_=function(a){var b=this.getMetaKey_({alt:-1!=a.indexOf("alt+"),shift:-1!=a.indexOf("shift+"),ctrl:-1!=a.indexOf("ctrl+")}),c=a.split(/\+(?!$)/);return a=c[c.length-1],{meta:b,key:a}},a.ShortcutService.prototype.getMetaKey_=function(a){var b=[];return["alt","ctrl","shift"].forEach(function(c){a[c]&&b.push(c)}),b.length>0?b.join("+"):"normal"},a.ShortcutService.prototype.onKeyUp_=function(a){if(!this.isInInput_(a)){var b=a.which,c=(a.target.nodeName.toUpperCase(),pskl.service.keyboard.KeycodeTranslator.toChar(b)),d=this.shortcuts_[c];if(d){var e=this.getMetaKey_({alt:this.isAltKeyPressed_(a),shift:this.isShiftKeyPressed_(a),ctrl:this.isCtrlKeyPressed_(a)}),f=d[e];if(f){var g=f(c);g!==!0&&a.preventDefault()}}}},a.ShortcutService.prototype.isInInput_=function(a){var b=a.target.nodeName.toUpperCase();return"INPUT"===b||"TEXTAREA"===b},a.ShortcutService.prototype.isCtrlKeyPressed_=function(a){return pskl.utils.UserAgent.isMac?a.metaKey:a.ctrlKey},a.ShortcutService.prototype.isShiftKeyPressed_=function(a){return a.shiftKey},a.ShortcutService.prototype.isAltKeyPressed_=function(a){return a.altKey}}(),function(){var a={191:"?",8:"back",27:"esc",38:"up",40:"down",46:"del",189:"-",187:"+"},b=$.namespace("pskl.service.keyboard");b.KeycodeTranslator={toChar:function(b){return b>=48&&57>=b?b-48+"":b>=65&&90>=b?(b-65+10).toString(36):a[b]}}}(),function(){var a=$.namespace("pskl.service.keyboard");a.CheatsheetService=function(){this.isDisplayed_=!1},a.CheatsheetService.prototype.init=function(){if(this.cheatsheetEl_=document.getElementById("cheatsheet-wrapper"),!this.cheatsheetEl_)throw"cheatsheetEl_ DOM element could not be retrieved";this.initMarkup_(),pskl.app.shortcutService.addShortcut("shift+?",this.toggleCheatsheet_.bind(this)),pskl.app.shortcutService.addShortcut("?",this.toggleCheatsheet_.bind(this));var a=$(".cheatsheet-link");a.click(this.toggleCheatsheet_.bind(this)),$.subscribe(Events.TOGGLE_HELP,this.toggleCheatsheet_.bind(this)),$.subscribe(Events.ESCAPE,this.onEscape_.bind(this))},a.CheatsheetService.prototype.toggleCheatsheet_=function(){this.isDisplayed_?this.hideCheatsheet_():this.showCheatsheet_()},a.CheatsheetService.prototype.onEscape_=function(){this.isDisplayed_&&this.hideCheatsheet_()},a.CheatsheetService.prototype.showCheatsheet_=function(){pskl.app.shortcutService.addShortcut("ESC",this.hideCheatsheet_.bind(this)),this.cheatsheetEl_.style.display="block",this.isDisplayed_=!0},a.CheatsheetService.prototype.hideCheatsheet_=function(){pskl.app.shortcutService.removeShortcut("ESC"),this.cheatsheetEl_.style.display="none",this.isDisplayed_=!1},a.CheatsheetService.prototype.initMarkup_=function(){this.initMarkupForTools_(),this.initMarkupForMisc_(),this.initMarkupForSelection_()},a.CheatsheetService.prototype.toDescriptor_=function(a,b,c){return pskl.utils.UserAgent.isMac&&(a=a.replace("ctrl","cmd")),{shortcut:a,description:b,icon:c}},a.CheatsheetService.prototype.getDomFromDescriptor_=function(a){var b=pskl.utils.Template.get("cheatsheet-shortcut-template"),c=pskl.utils.Template.replace(b,{shortcutIcon:a.icon,shortcutDescription:a.description,shortcutKey:a.shortcut});return pskl.utils.Template.createFromHTML(c)},a.CheatsheetService.prototype.initMarkupAbstract_=function(a,b){for(var c=$(b,this.cheatsheetEl_).get(0),d=0;da?1:-1,i=d>c?1:-1,j=f-g;;){if(e.push({col:a,row:c}),a==b&&c==d)break;var k=2*j;k>-g&&(j-=g,a+=h),f>k&&(j+=f,c+=i)}return e}}(),function(){var a=$.namespace("pskl.drawingtools");a.ShapeTool=function(){this.startCol=null,this.startRow=null,this.tooltipDescriptors=[{key:"shift",description:"Keep 1 to 1 ratio"}]},pskl.utils.inherit(a.ShapeTool,a.BaseTool),a.ShapeTool.prototype.applyToolAt=function(a,b,c,d,e){$.publish(Events.DRAG_START,[a,b]),this.startCol=a,this.startRow=b,e.setPixel(a,b,c)},a.ShapeTool.prototype.moveToolAt=function(a,b,c,d,e,f){var g=this.getCoordinates_(a,b,f);$.publish(Events.CURSOR_MOVED,[g.col,g.row]),e.clear(),c==Constants.TRANSPARENT_COLOR&&(c=Constants.SELECTION_TRANSPARENT_COLOR),this.draw_(g.col,g.row,c,e)},a.ShapeTool.prototype.releaseToolAt=function(a,b,c,d,e,f){e.clear();var g=this.getCoordinates_(a,b,f);this.draw_(g.col,g.row,c,d),$.publish(Events.DRAG_END,[a,b]),this.raiseSaveStateEvent({col:a,row:b,startCol:this.startCol,startRow:this.startRow,color:c})},a.ShapeTool.prototype.replay=function(a,b){this.startCol=b.startCol,this.startRow=b.startRow,this.draw_(b.col,b.row,b.color,a)},a.ShapeTool.prototype.getCoordinates_=function(a,b,c){return c.shiftKey?this.getScaledCoordinates_(a,b):{col:a,row:b}},a.ShapeTool.prototype.getScaledCoordinates_=function(a,b){var c=this.startCol-a,d=Math.abs(c),e=this.startRow-b,f=Math.abs(e),g=Math.min(d,f);return b=this.startRow-e/f*g,a=this.startCol-c/d*g,{col:a,row:b}},a.ShapeTool.prototype.draw_=Constants.ABSTRACT_FUNCTION}(),function(){var a=$.namespace("pskl.drawingtools");a.SimplePen=function(){this.toolId="tool-pen",this.helpText="Pen tool",this.previousCol=null,this.previousRow=null,this.pixels=[]},pskl.utils.inherit(a.SimplePen,a.BaseTool),a.SimplePen.prototype.applyToolAt=function(a,b,c,d,e){this.previousCol=a,this.previousRow=b,e.setPixel(a,b,c),c===Constants.TRANSPARENT_COLOR&&d.setPixel(a,b,c),this.pixels.push({col:a,row:b,color:c})},a.SimplePen.prototype.moveToolAt=function(a,b,c,d,e,f){if(Math.abs(a-this.previousCol)>1||Math.abs(b-this.previousRow)>1)for(var g=this.getLinePixels_(a,this.previousCol,b,this.previousRow),h=0,i=g.length;i>h;h++){var j=g[h];this.applyToolAt(j.col,j.row,c,d,e,f)}else this.applyToolAt(a,b,c,d,e,f);this.previousCol=a,this.previousRow=b},a.SimplePen.prototype.releaseToolAt=function(a,b,c,d){this.setPixelsToFrame_(d,this.pixels),this.raiseSaveStateEvent({pixels:this.pixels.slice(0),color:c}),this.resetUsedPixels_()},a.SimplePen.prototype.replay=function(a,b){this.setPixelsToFrame_(a,b.pixels,b.color)},a.SimplePen.prototype.setPixelsToFrame_=function(a,b){b.forEach(function(b){a.setPixel(b.col,b.row,b.color)})},a.SimplePen.prototype.resetUsedPixels_=function(){this.pixels=[]}}(),function(){var a=$.namespace("pskl.drawingtools"),b=3;a.Lighten=function(){this.superclass.constructor.call(this),this.toolId="tool-lighten",this.helpText="Lighten",this.tooltipDescriptors=[{key:"ctrl",description:"Darken"},{key:"shift",description:"Apply only once per pixel"}],this.usedPixels_={darken:{},lighten:{}}},pskl.utils.inherit(a.Lighten,a.SimplePen),a.Lighten.prototype.resetUsedPixels_=function(){this.usedPixels_={darken:{},lighten:{}},this.superclass.resetUsedPixels_.call(this)},a.Lighten.prototype.applyToolAt=function(a,c,d,e,f,g){var h=f.getPixel(a,c),i=e.getPixel(a,c),j=h===Constants.TRANSPARENT_COLOR?i:h,k=pskl.utils.UserAgent.isMac?g.metaKey:g.ctrlKey,l=g.shiftKey,m=j===Constants.TRANSPARENT_COLOR,n=k?this.usedPixels_.darken:this.usedPixels_.lighten,o=a+"-"+c,p=m||l&&n[o];if(p)d=window.tinycolor(j);else{var q=l?2*b:b;d=k?window.tinycolor.darken(j,q):window.tinycolor.lighten(j,q)}d&&(n[o]=!0,this.superclass.applyToolAt.call(this,a,c,d.toRgbString(),e,f,g))}}(),function(){var a=$.namespace("pskl.drawingtools");a.VerticalMirrorPen=function(){this.superclass.constructor.call(this),this.toolId="tool-vertical-mirror-pen",this.helpText="Vertical Mirror pen",this.tooltipDescriptors=[{key:"ctrl",description:"Use horizontal axis"},{key:"shift",description:"Use horizontal and vertical axis"}]},pskl.utils.inherit(a.VerticalMirrorPen,a.SimplePen),a.VerticalMirrorPen.prototype.backupPreviousPositions_=function(){this.backupPreviousCol=this.previousCol,this.backupPreviousRow=this.previousRow},a.VerticalMirrorPen.prototype.restorePreviousPositions_=function(){this.previousCol=this.backupPreviousCol,this.previousRow=this.backupPreviousRow},a.VerticalMirrorPen.prototype.applyToolAt=function(a,b,c,d,e,f){this.superclass.applyToolAt.call(this,a,b,c,d,e),this.backupPreviousPositions_();var g=this.getSymmetricCol_(a,d),h=this.getSymmetricRow_(b,d),i=pskl.utils.UserAgent.isMac?f.metaKey:f.ctrlKey;i||this.superclass.applyToolAt.call(this,g,b,c,d,e),(f.shiftKey||i)&&this.superclass.applyToolAt.call(this,a,h,c,d,e),f.shiftKey&&this.superclass.applyToolAt.call(this,g,h,c,d,e),this.restorePreviousPositions_()},a.VerticalMirrorPen.prototype.getSymmetricCol_=function(a,b){return b.getWidth()-a-1},a.VerticalMirrorPen.prototype.getSymmetricRow_=function(a,b){return b.getHeight()-a-1}}(),function(){var a=$.namespace("pskl.drawingtools");a.Eraser=function(){this.superclass.constructor.call(this),this.toolId="tool-eraser",this.helpText="Eraser tool"},pskl.utils.inherit(a.Eraser,a.SimplePen),a.Eraser.prototype.applyToolAt=function(a,b,c,d,e,f){this.superclass.applyToolAt.call(this,a,b,Constants.TRANSPARENT_COLOR,d,e,f)},a.Eraser.prototype.releaseToolAt=function(a,b,c,d,e,f){this.superclass.releaseToolAt.call(this,a,b,Constants.TRANSPARENT_COLOR,d,e,f)}}(),function(){var a=$.namespace("pskl.drawingtools");a.Stroke=function(){this.toolId="tool-stroke",this.helpText="Stroke tool",this.startCol=null,this.startRow=null},pskl.utils.inherit(a.Stroke,a.BaseTool),a.Stroke.prototype.applyToolAt=function(a,b,c,d,e){this.startCol=a,this.startRow=b,e.setPixel(a,b,c)},a.Stroke.prototype.moveToolAt=function(a,b,c,d,e){e.clear();for(var f=this.getLinePixels_(this.startCol,a,this.startRow,b),g=0;gi;i++)for(var j=0;h>j;j++){var k=i-a,l=j-b;e.shiftKey&&(k=(k+g)%g,l=(l+h)%h),f=d.containsPixel(k,l)?d.getPixel(k,l):Constants.TRANSPARENT_COLOR,c.setPixel(i,j,f)}},a.Move.prototype.releaseToolAt=function(a,b,c,d,e,f){this.moveToolAt(a,b,c,d,e,f),this.raiseSaveStateEvent({colDiff:a-this.startCol,rowDiff:b-this.startRow,shiftKey:f.shiftKey})},a.Move.prototype.replay=function(a,b){var c={shiftKey:b.shiftKey};this.shiftFrame(b.colDiff,b.rowDiff,a,a.clone(),c)}}(),function(){var a=$.namespace("pskl.drawingtools");a.BaseSelect=function(){this.secondaryToolId=pskl.drawingtools.Move.TOOL_ID,this.BodyRoot=$("body"),this.startCol=null,this.startRow=null,this.selection=null,this.tooltipDescriptors=[{description:"Drag the selection to move it. You may switch to other layers and frames."},{key:"ctrl+c",description:"Copy the selected area"},{key:"ctrl+v",description:"Paste the copied area"}]},pskl.utils.inherit(a.BaseSelect,a.BaseTool),a.BaseSelect.prototype.applyToolAt=function(a,b,c,d,e){this.startCol=a,this.startRow=b,this.lastCol=a,this.lastRow=b,this.isInSelection(a,b)?(this.mode="moveSelection",this.onSelectionDragStart_(a,b,c,d,e)):(this.mode="select",this.onSelectStart_(a,b,c,d,e))},a.BaseSelect.prototype.moveToolAt=function(a,b,c,d,e){"select"==this.mode?this.onSelect_(a,b,c,d,e):"moveSelection"==this.mode&&this.onSelectionDrag_(a,b,c,d,e)},a.BaseSelect.prototype.releaseToolAt=function(a,b,c,d,e){"select"==this.mode?this.onSelectEnd_(a,b,c,d,e):"moveSelection"==this.mode&&this.onSelectionDragEnd_(a,b,c,d,e)},a.BaseSelect.prototype.moveUnactiveToolAt=function(a,b,c,d,e){e.containsPixel(a,b)&&(this.isInSelection(a,b)?(this.BodyRoot.addClass(this.secondaryToolId),this.BodyRoot.removeClass(this.toolId)):(this.BodyRoot.addClass(this.toolId),this.BodyRoot.removeClass(this.secondaryToolId)))},a.BaseSelect.prototype.isInSelection=function(a,b){return this.selection&&this.selection.pixels.some(function(c){return c.col===a&&c.row===b})},a.BaseSelect.prototype.hideHighlightedPixel=function(){},a.BaseSelect.prototype.drawSelectionOnOverlay_=function(a){for(var b=this.selection.pixels,c=0,d=b.length;d>c;c++){var e=b[c],f=e.color&&e.color!==Constants.TRANSPARENT_COLOR,g=f?this.getTransparentVariant(e.color):Constants.SELECTION_TRANSPARENT_COLOR;a.setPixel(b[c].col,b[c].row,g)}},a.BaseSelect.prototype.getTransparentVariant=function(a){var b=window.tinycolor(a);return b=window.tinycolor.lighten(b,10),b.setAlpha(.5),b.toRgbString()},a.BaseSelect.prototype.onSelectStart_=function(){},a.BaseSelect.prototype.onSelect_=function(){},a.BaseSelect.prototype.onSelectEnd_=function(){},a.BaseSelect.prototype.onSelectionDragStart_=function(){},a.BaseSelect.prototype.onSelectionDrag_=function(a,b,c,d,e){{var f=a-this.lastCol,g=b-this.lastRow; -a-this.startCol,b-this.startRow}this.selection.move(f,g),e.clear(),this.drawSelectionOnOverlay_(e),this.lastCol=a,this.lastRow=b},a.BaseSelect.prototype.onSelectionDragEnd_=function(a,b,c,d,e){this.onSelectionDrag_(a,b,c,d,e)}}(),function(){var a=$.namespace("pskl.drawingtools");a.RectangleSelect=function(){this.toolId="tool-rectangle-select",this.helpText="Rectangle selection",a.BaseSelect.call(this),this.hasSelection=!1},pskl.utils.inherit(a.RectangleSelect,a.BaseSelect),a.RectangleSelect.prototype.onSelectStart_=function(a,b,c,d,e){this.hasSelection?(this.hasSelection=!1,e.clear(),$.publish(Events.SELECTION_DISMISSED)):(this.hasSelection=!0,$.publish(Events.DRAG_START,[a,b]),e.setPixel(a,b,c))},a.RectangleSelect.prototype.onSelect_=function(a,b,c,d,e){this.hasSelection&&(e.clear(),this.selection=new pskl.selection.RectangularSelection(this.startCol,this.startRow,a,b),$.publish(Events.SELECTION_CREATED,[this.selection]),this.drawSelectionOnOverlay_(e))},a.RectangleSelect.prototype.onSelectEnd_=function(a,b,c,d,e){this.hasSelection&&(this.onSelect_(a,b,c,d,e),$.publish(Events.DRAG_END,[a,b]))}}(),function(){var a=$.namespace("pskl.drawingtools");a.ShapeSelect=function(){this.toolId="tool-shape-select",this.helpText="Shape selection",a.BaseSelect.call(this)},pskl.utils.inherit(a.ShapeSelect,a.BaseSelect),a.ShapeSelect.prototype.onSelectStart_=function(a,b,c,d,e){$.publish(Events.SELECTION_DISMISSED),e.clear();var f=pskl.PixelUtils.getSimilarConnectedPixelsFromFrame(d,a,b);this.selection=new pskl.selection.ShapeSelection(f),$.publish(Events.SELECTION_CREATED,[this.selection]),this.drawSelectionOnOverlay_(e)}}(),function(){var a=$.namespace("pskl.drawingtools");a.ColorPicker=function(){this.toolId="tool-colorpicker",this.helpText="Color picker"},pskl.utils.inherit(a.ColorPicker,a.BaseTool),a.ColorPicker.prototype.applyToolAt=function(a,b,c,d,e,f){if(d.containsPixel(a,b)){var g=d.getPixel(a,b);f.button==Constants.LEFT_BUTTON?$.publish(Events.SELECT_PRIMARY_COLOR,[g]):f.button==Constants.RIGHT_BUTTON&&$.publish(Events.SELECT_SECONDARY_COLOR,[g])}}}(),function(){var a=$.namespace("pskl.drawingtools");a.ColorSwap=function(){this.toolId="tool-colorswap",this.helpText="Paint all pixels of the same color",this.tooltipDescriptors=[{key:"ctrl",description:"Apply to all layers"},{key:"shift",description:"Apply to all frames"}]},pskl.utils.inherit(a.ColorSwap,a.BaseTool),a.ColorSwap.prototype.applyToolAt=function(a,b,c,d,e,f){if(d.containsPixel(a,b)){var g=d.getPixel(a,b),h=pskl.utils.UserAgent.isMac?f.metaKey:f.ctrlKey,i=f.shiftKey;this.swapColors(g,c,h,i),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})}},a.ColorSwap.prototype.swapColors=function(a,b,c,d){var e=function(c,d,e,f){c==a&&(f.pixels[d][e]=b)},f=pskl.app.piskelController.getCurrentLayer(),g=pskl.app.piskelController.getCurrentFrameIndex();pskl.app.piskelController.getPiskel().getLayers().forEach(function(a){(c||a===f)&&a.getFrames().forEach(function(a,b){(d||b===g)&&(a.forEachPixel(e),a.version++)})})}}(),function(){var a=$.namespace("pskl");a.app={init:function(){this.isAppEngineVersion=!!pskl.appEngineToken_,this.shortcutService=new pskl.service.keyboard.ShortcutService,this.shortcutService.init();var a={height:Constants.DEFAULT.HEIGHT,width:Constants.DEFAULT.WIDTH},b=new pskl.model.piskel.Descriptor("New Piskel",""),c=new pskl.model.Piskel(a.width,a.height,b),d=new pskl.model.Layer("Layer 1"),e=new pskl.model.Frame(a.width,a.height);d.addFrame(e),c.addLayer(d),this.corePiskelController=new pskl.controller.piskel.PiskelController(c),this.corePiskelController.init(),this.piskelController=new pskl.controller.piskel.PublicPiskelController(this.corePiskelController),this.piskelController.init(),this.paletteImportService=new pskl.service.palette.PaletteImportService,this.paletteService=new pskl.service.palette.PaletteService,this.paletteController=new pskl.controller.PaletteController,this.paletteController.init(),this.currentColorsService=new pskl.service.CurrentColorsService(this.piskelController),this.currentColorsService.init(),this.palettesListController=new pskl.controller.PalettesListController(this.paletteController,this.currentColorsService),this.palettesListController.init(),this.cursorCoordinatesController=new pskl.controller.CursorCoordinatesController(this.piskelController),this.cursorCoordinatesController.init(),this.drawingController=new pskl.controller.DrawingController(this.piskelController,this.paletteController,$("#drawing-canvas-container")),this.drawingController.init(),this.animationController=new pskl.controller.AnimatedPreviewController(this.piskelController,$("#animated-preview-canvas-container")),this.animationController.init(),this.minimapController=new pskl.controller.MinimapController(this.piskelController,this.animationController,this.drawingController,$("#animated-preview-canvas-container")),this.minimapController.init(),this.previewFilmController=new pskl.controller.PreviewFilmController(this.piskelController,$("#preview-list")),this.previewFilmController.init(),this.layersListController=new pskl.controller.LayersListController(this.piskelController),this.layersListController.init(),this.settingsController=new pskl.controller.settings.SettingsController(this.piskelController),this.settingsController.init(),this.dialogsController=new pskl.controller.dialogs.DialogsController(this.piskelController),this.dialogsController.init(),this.toolController=new pskl.controller.ToolController,this.toolController.init(),this.selectionManager=new pskl.selection.SelectionManager(this.piskelController),this.selectionManager.init(),this.historyService=new pskl.service.HistoryService(this.corePiskelController),this.historyService.init(),this.notificationController=new pskl.controller.NotificationController,this.notificationController.init(),this.canvasBackgroundController=new pskl.controller.CanvasBackgroundController,this.canvasBackgroundController.init(),this.localStorageService=new pskl.service.LocalStorageService(this.piskelController),this.localStorageService.init(),this.imageUploadService=new pskl.service.ImageUploadService,this.imageUploadService.init(),this.cheatsheetService=new pskl.service.keyboard.CheatsheetService,this.cheatsheetService.init(),this.savedStatusService=new pskl.service.SavedStatusService(this.piskelController),this.savedStatusService.init(),this.backupService=new pskl.service.BackupService(this.piskelController),this.backupService.init(),this.beforeUnloadService=new pskl.service.BeforeUnloadService(this.piskelController),this.beforeUnloadService.init(),this.fileDropperService=new pskl.service.FileDropperService(this.piskelController,$("#drawing-canvas-container").get(0)),this.fileDropperService.init(),this.storageService=this.isAppEngineVersion?new pskl.service.AppEngineStorageService(this.piskelController):new pskl.service.GithubStorageService(this.piskelController),this.storageService.init();var f=new pskl.rendering.DrawingLoop;f.addCallback(this.render,this),f.start(),this.initTooltips_();var g=this.getPiskelInitData_();g&&g.piskel&&this.loadPiskel_(g.piskel,g.descriptor,g.fps),pskl.devtools&&pskl.devtools.init()},loadPiskel_:function(a,b,c){pskl.utils.serialization.Deserializer.deserialize(a,function(a){a.setDescriptor(b),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(c)})},getPiskelInitData_:function(){return pskl.appEnginePiskelData_},isLoggedIn:function(){var a=this.getPiskelInitData_();return a&&a.isLoggedIn},initTooltips_:function(){$("body").tooltip({selector:"[rel=tooltip]"})},render:function(a){this.drawingController.render(a),this.animationController.render(a),this.previewFilmController.render(a)},getFirstFrameAsPng:function(){var a=this.piskelController.getFrameAt(0),b=new pskl.rendering.CanvasRenderer(a,1);b.drawTransparentAs("rgba(0,0,0,0)");var c=b.render();return c.toDataURL("image/png")},getFramesheetAsPng:function(){var a=new pskl.rendering.PiskelRenderer(this.piskelController),b=a.renderAsCanvas();return b.toDataURL("image/png")}}}(),function(){var a=function(a,b,c){var d=a.clone(),e=a.getWidth(),f=a.getHeight();d.forEachPixel(function(d,g,h){b&&(g=e-g-1),c&&(h=f-h-1),a.pixels[g][h]=d}),a.version++};window.flip=function(b,c){var d=pskl.app.piskelController.getCurrentFrameIndex(),e=pskl.app.piskelController.getLayers();e.forEach(function(e){a(e.getFrameAt(d),b,c)}),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})},window.copyToAll=function(){var a=pskl.app.piskelController.getCurrentFrame(),b=pskl.app.piskelController.getCurrentLayer();b.getFrames().forEach(function(b){b!==a&&b.setPixels(a.getPixels())}),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})}}(); \ No newline at end of file diff --git a/palettes-proto/js/piskel-packaged-min.js b/palettes-proto/js/piskel-packaged-min.js deleted file mode 100644 index e2101726..00000000 --- a/palettes-proto/js/piskel-packaged-min.js +++ /dev/null @@ -1,13 +0,0 @@ -!function(a,b){function c(a){var b=ob[a]={};return $.each(a.split(bb),function(a,c){b[c]=!0}),b}function d(a,c,d){if(d===b&&1===a.nodeType){var e="data-"+c.replace(qb,"-$1").toLowerCase();if(d=a.getAttribute(e),"string"==typeof d){try{d="true"===d?!0:"false"===d?!1:"null"===d?null:+d+""===d?+d:pb.test(d)?$.parseJSON(d):d}catch(f){}$.data(a,c,d)}else d=b}return d}function e(a){var b;for(b in a)if(("data"!==b||!$.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function f(){return!1}function g(){return!0}function h(a){return!a||!a.parentNode||11===a.parentNode.nodeType}function i(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}function j(a,b,c){if(b=b||0,$.isFunction(b))return $.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return $.grep(a,function(a){return a===b===c});if("string"==typeof b){var d=$.grep(a,function(a){return 1===a.nodeType});if(Kb.test(b))return $.filter(b,d,!c);b=$.filter(b,d)}return $.grep(a,function(a){return $.inArray(a,b)>=0===c})}function k(a){var b=Nb.split("|"),c=a.createDocumentFragment();if(c.createElement)for(;b.length;)c.createElement(b.pop());return c}function l(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function m(a,b){if(1===b.nodeType&&$.hasData(a)){var c,d,e,f=$._data(a),g=$._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)$.event.add(b,c,h[c][d])}g.data&&(g.data=$.extend({},g.data))}}function n(a,b){var c;1===b.nodeType&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),$.support.html5Clone&&a.innerHTML&&!$.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Xb.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.selected=a.defaultSelected:"input"===c||"textarea"===c?b.defaultValue=a.defaultValue:"script"===c&&b.text!==a.text&&(b.text=a.text),b.removeAttribute($.expando))}function o(a){return"undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName("*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll("*"):[]}function p(a){Xb.test(a.type)&&(a.defaultChecked=a.checked)}function q(a,b){if(b in a)return b;for(var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=qc.length;e--;)if(b=qc[e]+c,b in a)return b;return d}function r(a,b){return a=b||a,"none"===$.css(a,"display")||!$.contains(a.ownerDocument,a)}function s(a,b){for(var c,d,e=[],f=0,g=a.length;g>f;f++)c=a[f],c.style&&(e[f]=$._data(c,"olddisplay"),b?(e[f]||"none"!==c.style.display||(c.style.display=""),""===c.style.display&&r(c)&&(e[f]=$._data(c,"olddisplay",w(c.nodeName)))):(d=cc(c,"display"),e[f]||"none"===d||$._data(c,"olddisplay",d)));for(f=0;g>f;f++)c=a[f],c.style&&(b&&"none"!==c.style.display&&""!==c.style.display||(c.style.display=b?e[f]||"":"none"));return a}function t(a,b,c){var d=jc.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function u(a,b,c,d){for(var e=c===(d?"border":"content")?4:"width"===b?1:0,f=0;4>e;e+=2)"margin"===c&&(f+=$.css(a,c+pc[e],!0)),d?("content"===c&&(f-=parseFloat(cc(a,"padding"+pc[e]))||0),"margin"!==c&&(f-=parseFloat(cc(a,"border"+pc[e]+"Width"))||0)):(f+=parseFloat(cc(a,"padding"+pc[e]))||0,"padding"!==c&&(f+=parseFloat(cc(a,"border"+pc[e]+"Width"))||0));return f}function v(a,b,c){var d="width"===b?a.offsetWidth:a.offsetHeight,e=!0,f=$.support.boxSizing&&"border-box"===$.css(a,"boxSizing");if(0>=d){if(d=cc(a,b),(0>d||null==d)&&(d=a.style[b]),kc.test(d))return d;e=f&&($.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+u(a,b,c||(f?"border":"content"),e)+"px"}function w(a){if(mc[a])return mc[a];var b=$("<"+a+">").appendTo(P.body),c=b.css("display");return b.remove(),("none"===c||""===c)&&(dc=P.body.appendChild(dc||$.extend(P.createElement("iframe"),{frameBorder:0,width:0,height:0})),ec&&dc.createElement||(ec=(dc.contentWindow||dc.contentDocument).document,ec.write(""),ec.close()),b=ec.body.appendChild(ec.createElement(a)),c=cc(b,"display"),P.body.removeChild(dc)),mc[a]=c,c}function x(a,b,c,d){var e;if($.isArray(b))$.each(b,function(b,e){c||tc.test(a)?d(a,e):x(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==$.type(b))d(a,b);else for(e in b)x(a+"["+e+"]",b[e],c,d)}function y(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(bb),h=0,i=g.length;if($.isFunction(c))for(;i>h;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function z(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;for(var h,i=a[f],j=0,k=i?i.length:0,l=a===Jc;k>j&&(l||!h);j++)h=i[j](c,d,e),"string"==typeof h&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=z(a,c,d,e,h,g)));return!l&&h||g["*"]||(h=z(a,c,d,e,"*",g)),h}function A(a,c){var d,e,f=$.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&$.extend(!0,a,e)}function B(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);for(;"*"===j[0];)j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}return g?(g!==j[0]&&j.unshift(g),d[g]):void 0}function C(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;if(a.dataFilter&&(b=a.dataFilter(b,a.dataType)),g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if("*"!==e){if("*"!==h&&h!==e){if(c=i[h+" "+e]||i["* "+e],!c)for(d in i)if(f=d.split(" "),f[1]===e&&(c=i[h+" "+f[0]]||i["* "+f[0]])){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function D(){try{return new a.XMLHttpRequest}catch(b){}}function E(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function F(){return setTimeout(function(){Uc=b},0),Uc=$.now()}function G(a,b){$.each(b,function(b,c){for(var d=($c[b]||[]).concat($c["*"]),e=0,f=d.length;f>e;e++)if(d[e].call(a,b,c))return})}function H(a,b,c){var d,e=0,f=Zc.length,g=$.Deferred().always(function(){delete h.elem}),h=function(){for(var b=Uc||F(),c=Math.max(0,i.startTime+i.duration-b),d=1-(c/i.duration||0),e=0,f=i.tweens.length;f>e;e++)i.tweens[e].run(d);return g.notifyWith(a,[i,d,c]),1>d&&f?c:(g.resolveWith(a,[i]),!1)},i=g.promise({elem:a,props:$.extend({},b),opts:$.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Uc||F(),duration:c.duration,tweens:[],createTween:function(b,c){var d=$.Tween(a,i.opts,b,c,i.opts.specialEasing[b]||i.opts.easing);return i.tweens.push(d),d},stop:function(b){for(var c=0,d=b?i.tweens.length:0;d>c;c++)i.tweens[c].run(1);return b?g.resolveWith(a,[i,b]):g.rejectWith(a,[i,b]),this}}),j=i.props;for(I(j,i.opts.specialEasing);f>e;e++)if(d=Zc[e].call(i,a,j,i.opts))return d;return G(i,j),$.isFunction(i.opts.start)&&i.opts.start.call(a,i),$.fx.timer($.extend(h,{anim:i,queue:i.opts.queue,elem:a})),i.progress(i.opts.progress).done(i.opts.done,i.opts.complete).fail(i.opts.fail).always(i.opts.always)}function I(a,b){var c,d,e,f,g;for(c in a)if(d=$.camelCase(c),e=b[d],f=a[c],$.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=$.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function J(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],p=a.nodeType&&r(a);c.queue||(j=$._queueHooks(a,"fx"),null==j.unqueued&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,$.queue(a,"fx").length||j.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],"inline"===$.css(a,"display")&&"none"===$.css(a,"float")&&($.support.inlineBlockNeedsLayout&&"inline"!==w(a.nodeName)?m.zoom=1:m.display="inline-block")),c.overflow&&(m.overflow="hidden",$.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(f=b[d],Wc.exec(f)){if(delete b[d],f===(p?"hide":"show"))continue;o.push(d)}if(g=o.length)for(h=$._data(a,"fxshow")||$._data(a,"fxshow",{}),p?$(a).show():l.done(function(){$(a).hide()}),l.done(function(){var b;$.removeData(a,"fxshow",!0);for(b in n)$.style(a,b,n[b])}),d=0;g>d;d++)e=o[d],i=l.createTween(e,p?h[e]:0),n[e]=h[e]||$.style(a,e),e in h||(h[e]=i.start,p&&(i.end=i.start,i.start="width"===e||"height"===e?1:0))}function K(a,b,c,d,e){return new K.prototype.init(a,b,c,d,e)}function L(a,b){for(var c,d={height:a},e=0;4>e;e+=2-b)c=pc[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function M(a){return $.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}var N,O,P=a.document,Q=a.location,R=a.navigator,S=a.jQuery,T=a.$,U=Array.prototype.push,V=Array.prototype.slice,W=Array.prototype.indexOf,X=Object.prototype.toString,Y=Object.prototype.hasOwnProperty,Z=String.prototype.trim,$=function(a,b){return new $.fn.init(a,b,N)},_=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,ab=/\S/,bb=/\s+/,cb=ab.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,db=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,eb=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,fb=/^[\],:{}\s]*$/,gb=/(?:^|:|,)(?:\s*\[)+/g,hb=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,ib=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,jb=/^-ms-/,kb=/-([\da-z])/gi,lb=function(a,b){return(b+"").toUpperCase()},mb=function(){P.addEventListener?(P.removeEventListener("DOMContentLoaded",mb,!1),$.ready()):"complete"===P.readyState&&(P.detachEvent("onreadystatechange",mb),$.ready())},nb={};$.fn=$.prototype={constructor:$,init:function(a,c,d){var e,f,g;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if("string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:db.exec(a),!e||!e[1]&&c)return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a);if(e[1])return c=c instanceof $?c[0]:c,g=c&&c.nodeType?c.ownerDocument||c:P,a=$.parseHTML(e[1],g,!0),eb.test(e[1])&&$.isPlainObject(c)&&this.attr.call(a,c,!0),$.merge(this,a);if(f=P.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return d.find(a);this.length=1,this[0]=f}return this.context=P,this.selector=a,this}return $.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),$.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return V.call(this)},get:function(a){return null==a?this.toArray():0>a?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=$.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,"find"===b?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return $.each(this,a,b)},ready:function(a){return $.ready.promise().done(a),this},eq:function(a){return a=+a,-1===a?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(V.apply(this,arguments),"slice",V.call(arguments).join(","))},map:function(a){return this.pushStack($.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:U,sort:[].sort,splice:[].splice},$.fn.init.prototype=$.fn,$.extend=$.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;for("boolean"==typeof h&&(k=h,h=arguments[1]||{},i=2),"object"==typeof h||$.isFunction(h)||(h={}),j===i&&(h=this,--i);j>i;i++)if(null!=(a=arguments[i]))for(c in a)d=h[c],e=a[c],h!==e&&(k&&e&&($.isPlainObject(e)||(f=$.isArray(e)))?(f?(f=!1,g=d&&$.isArray(d)?d:[]):g=d&&$.isPlainObject(d)?d:{},h[c]=$.extend(k,g,e)):e!==b&&(h[c]=e));return h},$.extend({noConflict:function(b){return a.$===$&&(a.$=T),b&&a.jQuery===$&&(a.jQuery=S),$},isReady:!1,readyWait:1,holdReady:function(a){a?$.readyWait++:$.ready(!0)},ready:function(a){if(a===!0?!--$.readyWait:!$.isReady){if(!P.body)return setTimeout($.ready,1);$.isReady=!0,a!==!0&&--$.readyWait>0||(O.resolveWith(P,[$]),$.fn.trigger&&$(P).trigger("ready").off("ready"))}},isFunction:function(a){return"function"===$.type(a)},isArray:Array.isArray||function(a){return"array"===$.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return null==a?String(a):nb[X.call(a)]||"object"},isPlainObject:function(a){if(!a||"object"!==$.type(a)||a.nodeType||$.isWindow(a))return!1;try{if(a.constructor&&!Y.call(a,"constructor")&&!Y.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||Y.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return a&&"string"==typeof a?("boolean"==typeof b&&(c=b,b=0),b=b||P,(d=eb.exec(a))?[b.createElement(d[1])]:(d=$.buildFragment([a],b,c?null:[]),$.merge([],(d.cacheable?$.clone(d.fragment):d.fragment).childNodes))):null},parseJSON:function(b){return b&&"string"==typeof b?(b=$.trim(b),a.JSON&&a.JSON.parse?a.JSON.parse(b):fb.test(b.replace(hb,"@").replace(ib,"]").replace(gb,""))?new Function("return "+b)():void $.error("Invalid JSON: "+b)):null},parseXML:function(c){var d,e;if(!c||"string"!=typeof c)return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return d&&d.documentElement&&!d.getElementsByTagName("parsererror").length||$.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&ab.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(jb,"ms-").replace(kb,lb)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||$.isFunction(a);if(d)if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;g>f&&c.apply(a[f++],d)!==!1;);else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;g>f&&c.call(a[f],f,a[f++])!==!1;);return a},trim:Z?function(a){return null==a?"":Z.call(a)}:function(a){return null==a?"":a.toString().replace(cb,"")},makeArray:function(a,b){var c,d=b||[];return null!=a&&(c=$.type(a),null==a.length||"string"===c||"function"===c||"regexp"===c||$.isWindow(a)?U.call(d,a):$.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(W)return W.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if("number"==typeof d)for(;d>f;f++)a[e++]=c[f];else for(;c[f]!==b;)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;for(c=!!c;g>f;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof $||i!==b&&"number"==typeof i&&(i>0&&a[0]&&a[i-1]||0===i||$.isArray(a));if(j)for(;i>h;h++)e=c(a[h],h,d),null!=e&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),null!=e&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return"string"==typeof c&&(d=a[c],c=a,a=d),$.isFunction(a)?(e=V.call(arguments,2),f=function(){return a.apply(c,e.concat(V.call(arguments)))},f.guid=a.guid=a.guid||f.guid||$.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=null==d,k=0,l=a.length;if(d&&"object"==typeof d){for(k in d)$.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){if(i=h===b&&$.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call($(a),c)}):(c.call(a,e),c=null)),c)for(;l>k;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),$.ready.promise=function(b){if(!O)if(O=$.Deferred(),"complete"===P.readyState||"loading"!==P.readyState&&P.addEventListener)setTimeout($.ready,1);else if(P.addEventListener)P.addEventListener("DOMContentLoaded",mb,!1),a.addEventListener("load",$.ready,!1);else{P.attachEvent("onreadystatechange",mb),a.attachEvent("onload",$.ready);var c=!1;try{c=null==a.frameElement&&P.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!$.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}$.ready()}}()}return O.promise(b)},$.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){nb["[object "+b+"]"]=b.toLowerCase()}),N=$(P);var ob={};$.Callbacks=function(a){a="string"==typeof a?ob[a]||c(a):$.extend({},a);var d,e,f,g,h,i,j=[],k=!a.once&&[],l=function(b){for(d=a.memory&&b,e=!0,i=g||0,g=0,h=j.length,f=!0;j&&h>i;i++)if(j[i].apply(b[0],b[1])===!1&&a.stopOnFalse){d=!1;break}f=!1,j&&(k?k.length&&l(k.shift()):d?j=[]:m.disable())},m={add:function(){if(j){var b=j.length;!function c(b){$.each(b,function(b,d){!$.isFunction(d)||a.unique&&m.has(d)?d&&d.length&&c(d):j.push(d)})}(arguments),f?h=j.length:d&&(g=b,l(d))}return this},remove:function(){return j&&$.each(arguments,function(a,b){for(var c;(c=$.inArray(b,j,c))>-1;)j.splice(c,1),f&&(h>=c&&h--,i>=c&&i--)}),this},has:function(a){return $.inArray(a,j)>-1},empty:function(){return j=[],this},disable:function(){return j=k=d=b,this},disabled:function(){return!j},lock:function(){return k=b,d||m.disable(),this},locked:function(){return!k},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],!j||e&&!k||(f?k.push(b):l(b)),this},fire:function(){return m.fireWith(this,arguments),this},fired:function(){return!!e}};return m},$.extend({Deferred:function(a){var b=[["resolve","done",$.Callbacks("once memory"),"resolved"],["reject","fail",$.Callbacks("once memory"),"rejected"],["notify","progress",$.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return $.Deferred(function(c){$.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]]($.isFunction(g)?function(){var a=g.apply(this,arguments);a&&$.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return"object"==typeof a?$.extend(a,d):d}},e={};return d.pipe=d.then,$.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b,c,d,e=0,f=V.call(arguments),g=f.length,h=1!==g||a&&$.isFunction(a.promise)?g:0,i=1===h?a:$.Deferred(),j=function(a,c,d){return function(e){c[a]=this,d[a]=arguments.length>1?V.call(arguments):e,d===b?i.notifyWith(c,d):--h||i.resolveWith(c,d)}};if(g>1)for(b=new Array(g),c=new Array(g),d=new Array(g);g>e;e++)f[e]&&$.isFunction(f[e].promise)?f[e].promise().done(j(e,d,f)).fail(i.reject).progress(j(e,c,b)):--h;return h||i.resolveWith(d,f),i.promise()}}),$.support=function(){var b,c,d,e,f,g,h,i,j,k,l,m=P.createElement("div");if(m.setAttribute("className","t"),m.innerHTML="
         
        a",c=m.getElementsByTagName("*"),d=m.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5",!c||!c.length||!d)return{};e=P.createElement("select"),f=e.appendChild(P.createElement("option")),g=m.getElementsByTagName("input")[0],b={leadingWhitespace:3===m.firstChild.nodeType,tbody:!m.getElementsByTagName("tbody").length,htmlSerialize:!!m.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:"/a"===d.getAttribute("href"),opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:"on"===g.value,optSelected:f.selected,getSetAttribute:"t"!==m.className,enctype:!!P.createElement("form").enctype,html5Clone:"<:nav>"!==P.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===P.compatMode,submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},g.checked=!0,b.noCloneChecked=g.cloneNode(!0).checked,e.disabled=!0,b.optDisabled=!f.disabled;try{delete m.test}catch(n){b.deleteExpando=!1}if(!m.addEventListener&&m.attachEvent&&m.fireEvent&&(m.attachEvent("onclick",l=function(){b.noCloneEvent=!1}),m.cloneNode(!0).fireEvent("onclick"),m.detachEvent("onclick",l)),g=P.createElement("input"),g.value="t",g.setAttribute("type","radio"),b.radioValue="t"===g.value,g.setAttribute("checked","checked"),g.setAttribute("name","t"),m.appendChild(g),h=P.createDocumentFragment(),h.appendChild(m.lastChild),b.checkClone=h.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=g.checked,h.removeChild(g),h.appendChild(m),m.attachEvent)for(j in{submit:!0,change:!0,focusin:!0})i="on"+j,k=i in m,k||(m.setAttribute(i,"return;"),k="function"==typeof m[i]),b[j+"Bubbles"]=k;return $(function(){var c,d,e,f,g="padding:0;margin:0;border:0;display:block;overflow:hidden;",h=P.getElementsByTagName("body")[0];h&&(c=P.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",h.insertBefore(c,h.firstChild),d=P.createElement("div"),c.appendChild(d),d.innerHTML="
        t
        ",e=d.getElementsByTagName("td"),e[0].style.cssText="padding:0;margin:0;border:0;display:none",k=0===e[0].offsetHeight,e[0].style.display="",e[1].style.display="none",b.reliableHiddenOffsets=k&&0===e[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=4===d.offsetWidth,b.doesNotIncludeMarginInBodyOffset=1!==h.offsetTop,a.getComputedStyle&&(b.pixelPosition="1%"!==(a.getComputedStyle(d,null)||{}).top,b.boxSizingReliable="4px"===(a.getComputedStyle(d,null)||{width:"4px"}).width,f=P.createElement("div"),f.style.cssText=d.style.cssText=g,f.style.marginRight=f.style.width="0",d.style.width="1px",d.appendChild(f),b.reliableMarginRight=!parseFloat((a.getComputedStyle(f,null)||{}).marginRight)),"undefined"!=typeof d.style.zoom&&(d.innerHTML="",d.style.cssText=g+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.style.overflow="visible",d.innerHTML="
        ",d.firstChild.style.width="5px",b.shrinkWrapBlocks=3!==d.offsetWidth,c.style.zoom=1),h.removeChild(c),c=d=e=f=null)}),h.removeChild(m),c=d=e=f=g=h=m=null,b}();var pb=/^(?:\{.*\}|\[.*\])$/,qb=/([A-Z])/g;$.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+($.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?$.cache[a[$.expando]]:a[$.expando],!!a&&!e(a)},data:function(a,c,d,e){if($.acceptData(a)){var f,g,h=$.expando,i="string"==typeof c,j=a.nodeType,k=j?$.cache:a,l=j?a[h]:a[h]&&h;if(l&&k[l]&&(e||k[l].data)||!i||d!==b)return l||(j?a[h]=l=$.deletedIds.pop()||++$.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=$.noop)),("object"==typeof c||"function"==typeof c)&&(e?k[l]=$.extend(k[l],c):k[l].data=$.extend(k[l].data,c)),f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[$.camelCase(c)]=d),i?(g=f[c],null==g&&(g=f[$.camelCase(c)])):g=f,g}},removeData:function(a,b,c){if($.acceptData(a)){var d,f,g,h=a.nodeType,i=h?$.cache:a,j=h?a[$.expando]:$.expando;if(i[j]){if(b&&(d=c?i[j]:i[j].data)){$.isArray(b)||(b in d?b=[b]:(b=$.camelCase(b),b=b in d?[b]:b.split(" ")));for(f=0,g=b.length;g>f;f++)delete d[b[f]];if(!(c?e:$.isEmptyObject)(d))return}(c||(delete i[j].data,e(i[j])))&&(h?$.cleanData([a],!0):$.support.deleteExpando||i!=i.window?delete i[j]:i[j]=null)}}},_data:function(a,b,c){return $.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&$.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),$.fn.extend({data:function(a,c){var e,f,g,h,i,j=this[0],k=0,l=null;if(a===b){if(this.length&&(l=$.data(j),1===j.nodeType&&!$._data(j,"parsedAttrs"))){for(g=j.attributes,i=g.length;i>k;k++)h=g[k].name,0===h.indexOf("data-")&&(h=$.camelCase(h.substring(5)),d(j,h,l[h]));$._data(j,"parsedAttrs",!0)}return l}return"object"==typeof a?this.each(function(){$.data(this,a)}):(e=a.split(".",2),e[1]=e[1]?"."+e[1]:"",f=e[1]+"!",$.access(this,function(c){return c===b?(l=this.triggerHandler("getData"+f,[e[0]]),l===b&&j&&(l=$.data(j,a),l=d(j,a,l)),l===b&&e[1]?this.data(e[0]):l):(e[1]=c,void this.each(function(){var b=$(this);b.triggerHandler("setData"+f,e),$.data(this,a,c),b.triggerHandler("changeData"+f,e)}))},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){$.removeData(this,a)})}}),$.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=$._data(a,b),c&&(!d||$.isArray(c)?d=$._data(a,b,$.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=$.queue(a,b),d=c.shift(),e=$._queueHooks(a,b),f=function(){$.dequeue(a,b)};"inprogress"===d&&(d=c.shift()),d&&("fx"===b&&c.unshift("inprogress"),delete e.stop,d.call(a,f,e)),!c.length&&e&&e.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return $._data(a,c)||$._data(a,c,{empty:$.Callbacks("once memory").add(function(){$.removeData(a,b+"queue",!0),$.removeData(a,c,!0)})})}}),$.fn.extend({queue:function(a,c){var d=2;return"string"!=typeof a&&(c=a,a="fx",d--),arguments.length1)},removeAttr:function(a){return this.each(function(){$.removeAttr(this,a)})},prop:function(a,b){return $.access(this,$.prop,a,b,arguments.length>1)},removeProp:function(a){return a=$.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if($.isFunction(a))return this.each(function(b){$(this).addClass(a.call(this,b,this.className))});if(a&&"string"==typeof a)for(b=a.split(bb),c=0,d=this.length;d>c;c++)if(e=this[c],1===e.nodeType)if(e.className||1!==b.length){for(f=" "+e.className+" ",g=0,h=b.length;h>g;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=$.trim(f)}else e.className=a;return this},removeClass:function(a){var c,d,e,f,g,h,i;if($.isFunction(a))return this.each(function(b){$(this).removeClass(a.call(this,b,this.className))});if(a&&"string"==typeof a||a===b)for(c=(a||"").split(bb),h=0,i=this.length;i>h;h++)if(e=this[h],1===e.nodeType&&e.className){for(d=(" "+e.className+" ").replace(ub," "),f=0,g=c.length;g>f;f++)for(;d.indexOf(" "+c[f]+" ")>-1;)d=d.replace(" "+c[f]+" "," ");e.className=a?$.trim(d):""}return this},toggleClass:function(a,b){var c=typeof a,d="boolean"==typeof b;return this.each($.isFunction(a)?function(c){$(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c)for(var e,f=0,g=$(this),h=b,i=a.split(bb);e=i[f++];)h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e);else("undefined"===c||"boolean"===c)&&(this.className&&$._data(this,"__className__",this.className),this.className=this.className||a===!1?"":$._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ub," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];{if(arguments.length)return e=$.isFunction(a),this.each(function(d){var f,g=$(this);1===this.nodeType&&(f=e?a.call(this,d,g.val()):a,null==f?f="":"number"==typeof f?f+="":$.isArray(f)&&(f=$.map(f,function(a){return null==a?"":a+""})),c=$.valHooks[this.type]||$.valHooks[this.nodeName.toLowerCase()],c&&"set"in c&&c.set(this,f,"value")!==b||(this.value=f))});if(f)return c=$.valHooks[f.type]||$.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,"string"==typeof d?d.replace(vb,""):null==d?"":d)}}}),$.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i="select-one"===a.type;if(0>f)return null;for(c=i?f:0,d=i?f+1:h.length;d>c;c++)if(e=h[c],!(!e.selected||($.support.optDisabled?e.disabled:null!==e.getAttribute("disabled"))||e.parentNode.disabled&&$.nodeName(e.parentNode,"optgroup"))){if(b=$(e).val(),i)return b;g.push(b)}return i&&!g.length&&h.length?$(h[f]).val():g},set:function(a,b){var c=$.makeArray(b);return $(a).find("option").each(function(){this.selected=$.inArray($(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(a&&3!==i&&8!==i&&2!==i)return e&&$.isFunction($.fn[c])?$(a)[c](d):"undefined"==typeof a.getAttribute?$.prop(a,c,d):(h=1!==i||!$.isXMLDoc(a),h&&(c=c.toLowerCase(),g=$.attrHooks[c]||(zb.test(c)?sb:rb)),d!==b?null===d?void $.removeAttr(a,c):g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d):g&&"get"in g&&h&&null!==(f=g.get(a,c))?f:(f=a.getAttribute(c),null===f?b:f))},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&1===a.nodeType)for(d=b.split(bb);g=0:void 0}})});var Bb=/^(?:textarea|input|select)$/i,Cb=/^([^\.]*|)(?:\.(.+)|)$/,Db=/(?:^|\s)hover(\.\S+|)\b/,Eb=/^key/,Fb=/^(?:mouse|contextmenu)|click/,Gb=/^(?:focusinfocus|focusoutblur)$/,Hb=function(a){return $.event.special.hover?a:a.replace(Db,"mouseenter$1 mouseleave$1")};$.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q;if(3!==a.nodeType&&8!==a.nodeType&&c&&d&&(g=$._data(a))){for(d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=$.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return"undefined"==typeof $||a&&$.event.triggered===a.type?b:$.event.dispatch.apply(h.elem,arguments)},h.elem=a),c=$.trim(Hb(c)).split(" "),j=0;j=0&&(q=q.slice(0,-1),h=!0),q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),e&&!$.event.customEvent[q]||$.event.global[q]))if(c="object"==typeof c?c[$.expando]?c:new $.Event(q,c):new $.Event(q),c.type=q,c.isTrigger=!0,c.exclusive=h,c.namespace=r.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,l=q.indexOf(":")<0?"on"+q:"",e){if(c.result=b,c.target||(c.target=e),d=null!=d?$.makeArray(d):[],d.unshift(c),m=$.event.special[q]||{},!m.trigger||m.trigger.apply(e,d)!==!1){if(o=[[e,m.bindType||q]],!f&&!m.noBubble&&!$.isWindow(e)){for(p=m.delegateType||q,j=Gb.test(p+q)?e:e.parentNode,k=e;j;j=j.parentNode)o.push([j,p]),k=j;k===(e.ownerDocument||P)&&o.push([k.defaultView||k.parentWindow||a,p])}for(i=0;id;d++)l=n[d],m=l.selector,i[m]===b&&(i[m]=g.is(m)),i[m]&&k.push(l);k.length&&s.push({elem:f,matches:k})}for(n.length>o&&s.push({elem:this,matches:n.slice(o)}),d=0;d0?this.on(b,null,a,c):this.trigger(b)},Eb.test(b)&&($.event.fixHooks[b]=$.event.keyHooks),Fb.test(b)&&($.event.fixHooks[b]=$.event.mouseHooks)}),function(a,b){function c(a,b,c,d){for(var e=0,f=b.length;f>e;e++)fb(a,b[e],c,d)}function d(a,b,d,e,f,g){var h,i=gb.setFilters[b.toLowerCase()];return i||fb.error(b),(a||!(h=f))&&c(a||"*",e,h=[],f),h.length>0?i(h,d,g):[]}function e(a,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=0,r=h.length,s=S.POS,t=new RegExp("^"+s.source+"(?!"+y+")","i"),u=function(){for(var a=1,c=arguments.length-2;c>a;a++)arguments[a]===b&&(i[a]=b)};r>q;q++){for(s.exec(""),a=h[q],l=[],k=0,m=g;i=s.exec(a);)p=s.lastIndex=i.index+i[0].length,p>k&&(o=a.slice(k,i.index),k=p,n=[e],I.test(o)&&(m&&(n=m),m=g),(j=O.test(o))&&(o=o.slice(0,-5).replace(I,"$&*")),i.length>1&&i[0].replace(t,u),m=d(o,i[1],i[2],n,m,j));m?(l=l.concat(m),(o=a.slice(k))&&")"!==o?I.test(o)?c(o,l,f,g):fb(o,e,f,g?g.concat(m):m):w.apply(f,l)):fb(a,e,f,g)}return 1===r?f:fb.uniqueSort(f)}function f(a,b,c){for(var d,e,f,g=[],h=0,i=K.exec(a),j=!i.pop()&&!i.pop(),k=j&&a.match(J)||[""],l=gb.preFilter,m=gb.filter,n=!c&&b!==p;null!=(e=k[h])&&j;h++)for(g.push(d=[]),n&&(e=" "+e);e;){j=!1,(i=I.exec(e))&&(e=e.slice(i[0].length),j=d.push({part:i.pop().replace(H," "),captures:i}));for(f in m)!(i=S[f].exec(e))||l[f]&&!(i=l[f](i,b,c))||(e=e.slice(i.shift().length),j=d.push({part:f,captures:i}));if(!j)break}return j||fb.error(a),g}function g(a,b,c){var d=b.dir,e=u++;return a||(a=function(a){return a===c}),b.first?function(b,c){for(;b=b[d];)if(1===b.nodeType)return a(b,c)&&b}:function(b,c){for(var f,g=e+"."+l,h=g+"."+k;b=b[d];)if(1===b.nodeType){if((f=b[x])===h)return b.sizset;if("string"==typeof f&&0===f.indexOf(g)){if(b.sizset)return b}else{if(b[x]=h,a(b,c))return b.sizset=!0,b;b.sizset=!1}}}}function h(a,b){return a?function(c,d){var e=b(c,d);return e&&a(e===!0?c:e,d)}:b}function i(a,b,c){for(var d,e,f=0;d=a[f];f++)gb.relative[d.part]?e=g(e,gb.relative[d.part],b):(d.captures.push(b,c),e=h(e,gb.filter[d.part].apply(null,d.captures)));return e}function j(a){return function(b,c){for(var d,e=0;d=a[e];e++)if(d(b,c))return!0;return!1}}var k,l,m,n,o,p=a.document,q=p.documentElement,r="undefined",s=!1,t=!0,u=0,v=[].slice,w=[].push,x=("sizcache"+Math.random()).replace(".",""),y="[\\x20\\t\\r\\n\\f]",z="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",A=z.replace("w","w#"),B="([*^$|!~]?=)",C="\\["+y+"*("+z+")"+y+"*(?:"+B+y+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+A+")|)|)"+y+"*\\]",D=":("+z+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",E=":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",F=y+"*([\\x20\\t\\r\\n\\f>+~])"+y+"*",G="(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|"+C+"|"+D.replace(2,7)+"|[^\\\\(),])+",H=new RegExp("^"+y+"+|((?:^|[^\\\\])(?:\\\\.)*)"+y+"+$","g"),I=new RegExp("^"+F),J=new RegExp(G+"?(?="+y+"*,|$)","g"),K=new RegExp("^(?:(?!,)(?:(?:^|,)"+y+"*"+G+")*?|"+y+"*(.*?))(\\)|$)"),L=new RegExp(G.slice(19,-6)+"\\x20\\t\\r\\n\\f>+~])+|"+F,"g"),M=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,N=/[\x20\t\r\n\f]*[+~]/,O=/:not\($/,P=/h\d/i,Q=/input|select|textarea|button/i,R=/\\(?!\\)/g,S={ID:new RegExp("^#("+z+")"),CLASS:new RegExp("^\\.("+z+")"),NAME:new RegExp("^\\[name=['\"]?("+z+")['\"]?\\]"),TAG:new RegExp("^("+z.replace("[-","[-\\*")+")"),ATTR:new RegExp("^"+C),PSEUDO:new RegExp("^"+D),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+y+"*(even|odd|(([+-]|)(\\d*)n|)"+y+"*(?:([+-]|)"+y+"*(\\d+)|))"+y+"*\\)|)","i"),POS:new RegExp(E,"ig"),needsContext:new RegExp("^"+y+"*[>+~]|"+E,"i")},T={},U=[],V={},W=[],X=function(a){return a.sizzleFilter=!0,a},Y=function(a){return function(b){return"input"===b.nodeName.toLowerCase()&&b.type===a}},Z=function(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}},_=function(a){var b=!1,c=p.createElement("div");try{b=a(c)}catch(d){}return c=null,b},ab=_(function(a){a.innerHTML="";var b=typeof a.lastChild.getAttribute("multiple");return"boolean"!==b&&"string"!==b}),bb=_(function(a){a.id=x+0,a.innerHTML="
        ",q.insertBefore(a,q.firstChild);var b=p.getElementsByName&&p.getElementsByName(x).length===2+p.getElementsByName(x+0).length;return o=!p.getElementById(x),q.removeChild(a),b}),cb=_(function(a){return a.appendChild(p.createComment("")),0===a.getElementsByTagName("*").length}),db=_(function(a){return a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!==r&&"#"===a.firstChild.getAttribute("href")}),eb=_(function(a){return a.innerHTML="",a.getElementsByClassName&&0!==a.getElementsByClassName("e").length?(a.lastChild.className="e",1!==a.getElementsByClassName("e").length):!1}),fb=function(a,b,c,d){c=c||[],b=b||p;var e,f,g,h,i=b.nodeType;if(1!==i&&9!==i)return[];if(!a||"string"!=typeof a)return c;if(g=ib(b),!g&&!d&&(e=M.exec(a)))if(h=e[1]){if(9===i){if(f=b.getElementById(h),!f||!f.parentNode)return c;if(f.id===h)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(h))&&jb(b,f)&&f.id===h)return c.push(f),c}else{if(e[2])return w.apply(c,v.call(b.getElementsByTagName(a),0)),c;if((h=e[3])&&eb&&b.getElementsByClassName)return w.apply(c,v.call(b.getElementsByClassName(h),0)),c}return mb(a,b,c,d,g)},gb=fb.selectors={cacheLength:50,match:S,order:["ID","TAG"],attrHandle:{},createPseudo:X,find:{ID:o?function(a,b,c){if(typeof b.getElementById!==r&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==r&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==r&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:cb?function(a,b){return typeof b.getElementsByTagName!==r?b.getElementsByTagName(a):void 0}:function(a,b){var c=b.getElementsByTagName(a);if("*"===a){for(var d,e=[],f=0;d=c[f];f++)1===d.nodeType&&e.push(d);return e}return c}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(R,""),a[3]=(a[4]||a[5]||"").replace(R,""),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1]?(a[2]||fb.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*("even"===a[2]||"odd"===a[2])),a[4]=+(a[6]+a[7]||"odd"===a[2])):a[2]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=a[4];return S.CHILD.test(a[0])?null:(c&&(b=K.exec(c))&&b.pop()&&(a[0]=a[0].slice(0,b[0].length-c.length-1),c=b[0].slice(0,-1)),a.splice(2,3,c||a[3]),a)}},filter:{ID:o?function(a){return a=a.replace(R,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(R,""),function(b){var c=typeof b.getAttributeNode!==r&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return"*"===a?function(){return!0}:(a=a.replace(R,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=T[a];return b||(b=T[a]=new RegExp("(^|"+y+")"+a+"("+y+"|$)"),U.push(a),U.length>gb.cacheLength&&delete T[U.shift()]),function(a){return b.test(a.className||typeof a.getAttribute!==r&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=fb.attr(d,a),f=e+"";if(null==e)return"!="===b;switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&0===f.indexOf(c);case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return null!=fb.attr(b,a)}},CHILD:function(a,b,c,d){if("nth"===a){var e=u++;return function(a){var b,f,g=0,h=a;if(1===c&&0===d)return!0;if(b=a.parentNode,b&&(b[x]!==e||!a.sizset)){for(h=b.firstChild;h&&(1!==h.nodeType||(h.sizset=++g,h!==a));h=h.nextSibling);b[x]=e}return f=a.sizset-d,0===c?0===f:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":for(;c=c.previousSibling;)if(1===c.nodeType)return!1;if("first"===a)return!0;c=b;case"last":for(;c=c.nextSibling;)if(1===c.nodeType)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e=gb.pseudos[a]||gb.pseudos[a.toLowerCase()];return e||fb.error("unsupported pseudo: "+a),e.sizzleFilter?e(b,c,d):e}},pseudos:{not:X(function(a,b,c){var d=lb(a.replace(H,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!gb.pseudos.empty(a)},empty:function(a){var b;for(a=a.firstChild;a;){if(a.nodeName>"@"||3===(b=a.nodeType)||4===b)return!1;a=a.nextSibling}return!0},contains:X(function(a){return function(b){return(b.textContent||b.innerText||kb(b)).indexOf(a)>-1}}),has:X(function(a){return function(b){return fb(a,b).length>0}}),header:function(a){return P.test(a.nodeName)},text:function(a){var b,c;return"input"===a.nodeName.toLowerCase()&&"text"===(b=a.type)&&(null==(c=a.getAttribute("type"))||c.toLowerCase()===b)},radio:Y("radio"),checkbox:Y("checkbox"),file:Y("file"),password:Y("password"),image:Y("image"),submit:Z("submit"),reset:Z("reset"),button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},input:function(a){return Q.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return!(a!==b.activeElement||b.hasFocus&&!b.hasFocus()||!a.type&&!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(a,b,c){for(var d=[],e=c?1:0,f=a.length;f>e;e+=2)d.push(a[e]);return d},odd:function(a,b,c){for(var d=[],e=c?0:1,f=a.length;f>e;e+=2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}};gb.setFilters.nth=gb.setFilters.eq,gb.filters=gb.pseudos,db||(gb.attrHandle={href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}}),bb&&(gb.order.push("NAME"),gb.find.NAME=function(a,b){return typeof b.getElementsByName!==r?b.getElementsByName(a):void 0}),eb&&(gb.order.splice(1,0,"CLASS"),gb.find.CLASS=function(a,b,c){return typeof b.getElementsByClassName===r||c?void 0:b.getElementsByClassName(a)});try{v.call(q.childNodes,0)[0].nodeType}catch(hb){v=function(a){for(var b,c=[];b=this[a];a++)c.push(b);return c}}var ib=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},jb=fb.contains=q.compareDocumentPosition?function(a,b){return!!(16&a.compareDocumentPosition(b))}:q.contains?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b.parentNode;return a===d||!!(d&&1===d.nodeType&&c.contains&&c.contains(d))}:function(a,b){for(;b=b.parentNode;)if(b===a)return!0;return!1},kb=fb.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(1===e||9===e||11===e){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=kb(a)}else if(3===e||4===e)return a.nodeValue}else for(;b=a[d];d++)c+=kb(b);return c};fb.attr=function(a,b){var c,d=ib(a);return d||(b=b.toLowerCase()),gb.attrHandle[b]?gb.attrHandle[b](a):ab||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?"boolean"==typeof a[b]?a[b]?b:null:c.specified?c.value:null:null)},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},[0,0].sort(function(){return t=0}),q.compareDocumentPosition?m=function(a,b){return a===b?(s=!0,0):(a.compareDocumentPosition&&b.compareDocumentPosition?4&a.compareDocumentPosition(b):a.compareDocumentPosition)?-1:1}:(m=function(a,b){if(a===b)return s=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return n(a,b);if(!g)return-1;if(!h)return 1;for(;i;)e.unshift(i),i=i.parentNode;for(i=h;i;)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;c>j&&d>j;j++)if(e[j]!==f[j])return n(e[j],f[j]);return j===c?n(a,f[j],-1):n(e[j],b,1)},n=function(a,b,c){if(a===b)return c;for(var d=a.nextSibling;d;){if(d===b)return-1;d=d.nextSibling}return 1}),fb.uniqueSort=function(a){var b,c=1;if(m&&(s=t,a.sort(m),s))for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a};var lb=fb.compile=function(a,b,c){var d,e,g,h=V[a];if(h&&h.context===b)return h;for(e=f(a,b,c),g=0;d=e[g];g++)e[g]=i(d,b,c);return h=V[a]=j(e),h.context=b,h.runs=h.dirruns=0,W.push(a),W.length>gb.cacheLength&&delete V[W.shift()],h};fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){return fb(b,null,null,[a]).length>0};var mb=function(a,b,c,d,f){a=a.replace(H,"$1");var g,h,i,j,m,n,o,p,q,r=a.match(J),s=a.match(L),t=b.nodeType;if(S.POS.test(a))return e(a,b,c,d,r);if(d)g=v.call(d,0);else if(r&&1===r.length){if(s.length>1&&9===t&&!f&&(r=S.ID.exec(s[0]))){if(b=gb.find.ID(r[1],b,f)[0],!b)return c;a=a.slice(s.shift().length)}for(p=(r=N.exec(s[0]))&&!r.index&&b.parentNode||b,q=s.pop(),n=q.split(":not")[0],i=0,j=gb.order.length;j>i;i++)if(o=gb.order[i],r=S[o].exec(n)){if(g=gb.find[o]((r[1]||"").replace(R,""),p,f),null==g)continue;n===q&&(a=a.slice(0,a.length-q.length)+n.replace(S[o],""),a||w.apply(c,v.call(g,0)));break}}if(a)for(h=lb(a,b,f),l=h.dirruns++,null==g&&(g=gb.find.TAG("*",N.test(a)&&b.parentNode||b)),i=0;m=g[i];i++)k=h.runs++,h(m,b)&&c.push(m);return c};p.querySelectorAll&&!function(){var a,b=mb,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=q.matchesSelector||q.mozMatchesSelector||q.webkitMatchesSelector||q.oMatchesSelector||q.msMatchesSelector;_(function(a){a.innerHTML="",a.querySelectorAll("[selected]").length||e.push("\\["+y+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),_(function(a){a.innerHTML="

        ",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+y+"*(?:\"\"|'')"),a.innerHTML="",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),mb=function(a,d,f,g,h){if(!(g||h||e&&e.test(a)))if(9===d.nodeType)try{return w.apply(f,v.call(d.querySelectorAll(a),0)),f}catch(i){}else if(1===d.nodeType&&"object"!==d.nodeName.toLowerCase()){var j=d.getAttribute("id"),k=j||x,l=N.test(a)&&d.parentNode||d;j?k=k.replace(c,"\\$&"):d.setAttribute("id",k);try{return w.apply(f,v.call(l.querySelectorAll(a.replace(J,"[id='"+k+"'] $&")),0)),f}catch(i){}finally{j||d.removeAttribute("id")}}return b(a,d,f,g,h)},g&&(_(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push(gb.match.PSEUDO)}catch(c){}}),f=new RegExp(f.join("|")),fb.matchesSelector=function(b,c){if(c=c.replace(d,"='$1']"),!(ib(b)||f.test(c)||e&&e.test(c)))try{var h=g.call(b,c);if(h||a||b.document&&11!==b.document.nodeType)return h}catch(i){}return fb(c,null,null,[b]).length>0})}(),fb.attr=$.attr,$.find=fb,$.expr=fb.selectors,$.expr[":"]=$.expr.pseudos,$.unique=fb.uniqueSort,$.text=fb.getText,$.isXMLDoc=fb.isXML,$.contains=fb.contains}(a);var Ib=/Until$/,Jb=/^(?:parents|prev(?:Until|All))/,Kb=/^.[^:#\[\.,]*$/,Lb=$.expr.match.needsContext,Mb={children:!0,contents:!0,next:!0,prev:!0};$.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if("string"!=typeof a)return $(a).filter(function(){for(b=0,c=h.length;c>b;b++)if($.contains(h[b],this))return!0});for(g=this.pushStack("","find",a),b=0,c=this.length;c>b;b++)if(d=g.length,$.find(a,this[b],g),b>0)for(e=d;ef;f++)if(g[f]===g[e]){g.splice(e--,1);break}return g},has:function(a){var b,c=$(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if($.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(j(this,a,!1),"not",a)},filter:function(a){return this.pushStack(j(this,a,!0),"filter",a)},is:function(a){return!!a&&("string"==typeof a?Lb.test(a)?$(a,this.context).index(this[0])>=0:$.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=Lb.test(a)||"string"!=typeof a?$(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c.ownerDocument&&c!==b&&11!==c.nodeType;){if(g?g.index(c)>-1:$.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}return f=f.length>1?$.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?"string"==typeof a?$.inArray(this[0],$(a)):$.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c="string"==typeof a?$(a,b):$.makeArray(a&&a.nodeType?[a]:a),d=$.merge(this.get(),c);return this.pushStack(h(c[0])||h(d[0])?d:$.unique(d))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}}),$.fn.andSelf=$.fn.addBack,$.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return $.dir(a,"parentNode")},parentsUntil:function(a,b,c){return $.dir(a,"parentNode",c)},next:function(a){return i(a,"nextSibling")},prev:function(a){return i(a,"previousSibling")},nextAll:function(a){return $.dir(a,"nextSibling")},prevAll:function(a){return $.dir(a,"previousSibling")},nextUntil:function(a,b,c){return $.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return $.dir(a,"previousSibling",c)},siblings:function(a){return $.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return $.sibling(a.firstChild)},contents:function(a){return $.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:$.merge([],a.childNodes)}},function(a,b){$.fn[a]=function(c,d){var e=$.map(this,b,c);return Ib.test(a)||(d=c),d&&"string"==typeof d&&(e=$.filter(d,e)),e=this.length>1&&!Mb[a]?$.unique(e):e,this.length>1&&Jb.test(a)&&(e=e.reverse()),this.pushStack(e,a,V.call(arguments).join(","))}}),$.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),1===b.length?$.find.matchesSelector(b[0],a)?[b[0]]:[]:$.find.matches(a,b)},dir:function(a,c,d){for(var e=[],f=a[c];f&&9!==f.nodeType&&(d===b||1!==f.nodeType||!$(f).is(d));)1===f.nodeType&&e.push(f),f=f[c];return e},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}});var Nb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",Ob=/ jQuery\d+="(?:null|\d+)"/g,Pb=/^\s+/,Qb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Rb=/<([\w:]+)/,Sb=/]","i"),Xb=/^(?:checkbox|radio)$/,Yb=/checked\s*(?:[^=]|=\s*.checked.)/i,Zb=/\/(java|ecma)script/i,$b=/^\s*\s*$/g,_b={option:[1,""],legend:[1,"
        ","
        "],thead:[1,"","
        "],tr:[2,"","
        "],td:[3,"","
        "],col:[2,"","
        "],area:[1,"",""],_default:[0,"",""]},ac=k(P),bc=ac.appendChild(P.createElement("div"));_b.optgroup=_b.option,_b.tbody=_b.tfoot=_b.colgroup=_b.caption=_b.thead,_b.th=_b.td,$.support.htmlSerialize||(_b._default=[1,"X
        ","
        "]),$.fn.extend({text:function(a){return $.access(this,function(a){return a===b?$.text(this):this.empty().append((this[0]&&this[0].ownerDocument||P).createTextNode(a)) -},null,a,arguments.length)},wrapAll:function(a){if($.isFunction(a))return this.each(function(b){$(this).wrapAll(a.call(this,b))});if(this[0]){var b=$(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){for(var a=this;a.firstChild&&1===a.firstChild.nodeType;)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each($.isFunction(a)?function(b){$(this).wrapInner(a.call(this,b))}:function(){var b=$(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=$.isFunction(a);return this.each(function(c){$(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){$.nodeName(this,"body")||$(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(1===this.nodeType||11===this.nodeType)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(1===this.nodeType||11===this.nodeType)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!h(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=$.clean(arguments);return this.pushStack($.merge(a,this),"before",this.selector)}},after:function(){if(!h(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=$.clean(arguments);return this.pushStack($.merge(this,a),"after",this.selector)}},remove:function(a,b){for(var c,d=0;null!=(c=this[d]);d++)(!a||$.filter(a,[c]).length)&&(b||1!==c.nodeType||($.cleanData(c.getElementsByTagName("*")),$.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)for(1===a.nodeType&&$.cleanData(a.getElementsByTagName("*"));a.firstChild;)a.removeChild(a.firstChild);return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return $.clone(this,a,b)})},html:function(a){return $.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return 1===c.nodeType?c.innerHTML.replace(Ob,""):b;if(!("string"!=typeof a||Ub.test(a)||!$.support.htmlSerialize&&Wb.test(a)||!$.support.leadingWhitespace&&Pb.test(a)||_b[(Rb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(Qb,"<$1>");try{for(;e>d;d++)c=this[d]||{},1===c.nodeType&&($.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return h(this[0])?this.length?this.pushStack($($.isFunction(a)?a():a),"replaceWith",a):this:$.isFunction(a)?this.each(function(b){var c=$(this),d=c.html();c.replaceWith(a.call(this,b,d))}):("string"!=typeof a&&(a=$(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;$(this).remove(),b?$(b).before(a):$(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],m=this.length;if(!$.support.checkClone&&m>1&&"string"==typeof j&&Yb.test(j))return this.each(function(){$(this).domManip(a,c,d)});if($.isFunction(j))return this.each(function(e){var f=$(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){if(e=$.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,1===g.childNodes.length&&(g=f),f)for(c=c&&$.nodeName(f,"tr"),h=e.cacheable||m-1;m>i;i++)d.call(c&&$.nodeName(this[i],"table")?l(this[i],"tbody"):this[i],i===h?g:$.clone(g,!0,!0));g=f=null,k.length&&$.each(k,function(a,b){b.src?$.ajax?$.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):$.error("no ajax"):$.globalEval((b.text||b.textContent||b.innerHTML||"").replace($b,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),$.buildFragment=function(a,c,d){var e,f,g,h=a[0];return c=c||P,c=(c[0]||c).ownerDocument||c[0]||c,"undefined"==typeof c.createDocumentFragment&&(c=P),!(1===a.length&&"string"==typeof h&&h.length<512&&c===P&&"<"===h.charAt(0))||Vb.test(h)||!$.support.checkClone&&Yb.test(h)||!$.support.html5Clone&&Wb.test(h)||(f=!0,e=$.fragments[h],g=e!==b),e||(e=c.createDocumentFragment(),$.clean(a,c,e,d),f&&($.fragments[h]=g&&e)),{fragment:e,cacheable:f}},$.fragments={},$.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){$.fn[a]=function(c){var d,e=0,f=[],g=$(c),h=g.length,i=1===this.length&&this[0].parentNode;if((null==i||i&&11===i.nodeType&&1===i.childNodes.length)&&1===h)return g[b](this[0]),this;for(;h>e;e++)d=(e>0?this.clone(!0):this).get(),$(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),$.extend({clone:function(a,b,c){var d,e,f,g;if($.support.html5Clone||$.isXMLDoc(a)||!Wb.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bc.innerHTML=a.outerHTML,bc.removeChild(g=bc.firstChild)),!($.support.noCloneEvent&&$.support.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||$.isXMLDoc(a)))for(n(a,g),d=o(a),e=o(g),f=0;d[f];++f)e[f]&&n(d[f],e[f]);if(b&&(m(a,g),c))for(d=o(a),e=o(g),f=0;d[f];++f)m(d[f],e[f]);return d=e=null,g},clean:function(a,b,c,d){var e,f,g,h,i,j,l,m,n,o,q,r=0,s=[];for(b&&"undefined"!=typeof b.createDocumentFragment||(b=P),f=b===P&∾null!=(g=a[r]);r++)if("number"==typeof g&&(g+=""),g){if("string"==typeof g)if(Tb.test(g)){for(f=f||k(b),l=l||f.appendChild(b.createElement("div")),g=g.replace(Qb,"<$1>"),h=(Rb.exec(g)||["",""])[1].toLowerCase(),i=_b[h]||_b._default,j=i[0],l.innerHTML=i[1]+g+i[2];j--;)l=l.lastChild;if(!$.support.tbody)for(m=Sb.test(g),n="table"!==h||m?""!==i[1]||m?[]:l.childNodes:l.firstChild&&l.firstChild.childNodes,e=n.length-1;e>=0;--e)$.nodeName(n[e],"tbody")&&!n[e].childNodes.length&&n[e].parentNode.removeChild(n[e]);!$.support.leadingWhitespace&&Pb.test(g)&&l.insertBefore(b.createTextNode(Pb.exec(g)[0]),l.firstChild),g=l.childNodes,l=f.lastChild}else g=b.createTextNode(g);g.nodeType?s.push(g):s=$.merge(s,g)}if(l&&(f.removeChild(l),g=l=f=null),!$.support.appendChecked)for(r=0;null!=(g=s[r]);r++)$.nodeName(g,"input")?p(g):"undefined"!=typeof g.getElementsByTagName&&$.grep(g.getElementsByTagName("input"),p);if(c)for(o=function(a){return!a.type||Zb.test(a.type)?d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a):void 0},r=0;null!=(g=s[r]);r++)$.nodeName(g,"script")&&o(g)||(c.appendChild(g),"undefined"!=typeof g.getElementsByTagName&&(q=$.grep($.merge([],g.getElementsByTagName("script")),o),s.splice.apply(s,[r+1,0].concat(q)),r+=q.length));return s},cleanData:function(a,b){for(var c,d,e,f,g=0,h=$.expando,i=$.cache,j=$.support.deleteExpando,k=$.event.special;null!=(e=a[g]);g++)if((b||$.acceptData(e))&&(d=e[h],c=d&&i[d])){if(c.events)for(f in c.events)k[f]?$.event.remove(e,f):$.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,$.deletedIds.push(d))}}}),function(){var a,b;$.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=$.uaMatch(R.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.webkit&&(b.safari=!0),$.browser=b,$.sub=function(){function a(b,c){return new a.fn.init(b,c)}$.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(c,d){return d&&d instanceof $&&!(d instanceof a)&&(d=a(d)),$.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(P);return a}}();var cc,dc,ec,fc=/alpha\([^)]*\)/i,gc=/opacity=([^)]*)/,hc=/^(top|right|bottom|left)$/,ic=/^margin/,jc=new RegExp("^("+_+")(.*)$","i"),kc=new RegExp("^("+_+")(?!px)[a-z%]+$","i"),lc=new RegExp("^([-+])=("+_+")","i"),mc={},nc={position:"absolute",visibility:"hidden",display:"block"},oc={letterSpacing:0,fontWeight:400,lineHeight:1},pc=["Top","Right","Bottom","Left"],qc=["Webkit","O","Moz","ms"],rc=$.fn.toggle;$.fn.extend({css:function(a,c){return $.access(this,function(a,c,d){return d!==b?$.style(a,c,d):$.css(a,c)},a,c,arguments.length>1)},show:function(){return s(this,!0)},hide:function(){return s(this)},toggle:function(a,b){var c="boolean"==typeof a;return $.isFunction(a)&&$.isFunction(b)?rc.apply(this,arguments):this.each(function(){(c?a:r(this))?$(this).show():$(this).hide()})}}),$.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=cc(a,"opacity");return""===c?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":$.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var f,g,h,i=$.camelCase(c),j=a.style;if(c=$.cssProps[i]||($.cssProps[i]=q(j,i)),h=$.cssHooks[c]||$.cssHooks[i],d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];if(g=typeof d,"string"===g&&(f=lc.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat($.css(a,c)),g="number"),!(null==d||"number"===g&&isNaN(d)||("number"!==g||$.cssNumber[i]||(d+="px"),h&&"set"in h&&(d=h.set(a,d,e))===b)))try{j[c]=d}catch(k){}}},css:function(a,c,d,e){var f,g,h,i=$.camelCase(c);return c=$.cssProps[i]||($.cssProps[i]=q(a.style,i)),h=$.cssHooks[c]||$.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=cc(a,c)),"normal"===f&&c in oc&&(f=oc[c]),d||e!==b?(g=parseFloat(f),d||$.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?cc=function(a,b){var c,d,e,f,g=getComputedStyle(a,null),h=a.style;return g&&(c=g[b],""!==c||$.contains(a.ownerDocument.documentElement,a)||(c=$.style(a,b)),kc.test(c)&&ic.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=c,c=g.width,h.width=d,h.minWidth=e,h.maxWidth=f)),c}:P.documentElement.currentStyle&&(cc=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return null==e&&f&&f[b]&&(e=f[b]),kc.test(e)&&!hc.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left="fontSize"===b?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),""===e?"auto":e}),$.each(["height","width"],function(a,b){$.cssHooks[b]={get:function(a,c,d){return c?0!==a.offsetWidth||"none"!==cc(a,"display")?v(a,b,d):$.swap(a,nc,function(){return v(a,b,d)}):void 0},set:function(a,c,d){return t(a,c,d?u(a,b,d,$.support.boxSizing&&"border-box"===$.css(a,"boxSizing")):0)}}}),$.support.opacity||($.cssHooks.opacity={get:function(a,b){return gc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=$.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,b>=1&&""===$.trim(f.replace(fc,""))&&c.removeAttribute&&(c.removeAttribute("filter"),d&&!d.filter)||(c.filter=fc.test(f)?f.replace(fc,e):f+" "+e)}}),$(function(){$.support.reliableMarginRight||($.cssHooks.marginRight={get:function(a,b){return $.swap(a,{display:"inline-block"},function(){return b?cc(a,"marginRight"):void 0})}}),!$.support.pixelPosition&&$.fn.position&&$.each(["top","left"],function(a,b){$.cssHooks[b]={get:function(a,c){if(c){var d=cc(a,b);return kc.test(d)?$(a).position()[b]+"px":d}}}})}),$.expr&&$.expr.filters&&($.expr.filters.hidden=function(a){return 0===a.offsetWidth&&0===a.offsetHeight||!$.support.reliableHiddenOffsets&&"none"===(a.style&&a.style.display||cc(a,"display"))},$.expr.filters.visible=function(a){return!$.expr.filters.hidden(a)}),$.each({margin:"",padding:"",border:"Width"},function(a,b){$.cssHooks[a+b]={expand:function(c){var d,e="string"==typeof c?c.split(" "):[c],f={};for(d=0;4>d;d++)f[a+pc[d]+b]=e[d]||e[d-2]||e[0];return f}},ic.test(a)||($.cssHooks[a+b].set=t)});var sc=/%20/g,tc=/\[\]$/,uc=/\r?\n/g,vc=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,wc=/^(?:select|textarea)/i;$.fn.extend({serialize:function(){return $.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?$.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||wc.test(this.nodeName)||vc.test(this.type))}).map(function(a,b){var c=$(this).val();return null==c?null:$.isArray(c)?$.map(c,function(a){return{name:b.name,value:a.replace(uc,"\r\n")}}):{name:b.name,value:c.replace(uc,"\r\n")}}).get()}}),$.param=function(a,c){var d,e=[],f=function(a,b){b=$.isFunction(b)?b():null==b?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(c===b&&(c=$.ajaxSettings&&$.ajaxSettings.traditional),$.isArray(a)||a.jquery&&!$.isPlainObject(a))$.each(a,function(){f(this.name,this.value)});else for(d in a)x(d,a[d],c,f);return e.join("&").replace(sc,"+")};var xc,yc,zc=/#.*$/,Ac=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Bc=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,Cc=/^(?:GET|HEAD)$/,Dc=/^\/\//,Ec=/\?/,Fc=/)<[^<]*)*<\/script>/gi,Gc=/([?&])_=[^&]*/,Hc=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Ic=$.fn.load,Jc={},Kc={},Lc=["*/"]+["*"];try{xc=Q.href}catch(Mc){xc=P.createElement("a"),xc.href="",xc=xc.href}yc=Hc.exec(xc.toLowerCase())||[],$.fn.load=function(a,c,d){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),$.isFunction(c)?(d=c,c=b):"object"==typeof c&&(f="POST"),$.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?$("
        ").append(a.replace(Fc,"")).find(e):a)}),this},$.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){$.fn[b]=function(a){return this.on(b,a)}}),$.each(["get","post"],function(a,c){$[c]=function(a,d,e,f){return $.isFunction(d)&&(f=f||e,e=d,d=b),$.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),$.extend({getScript:function(a,c){return $.get(a,b,c,"script")},getJSON:function(a,b,c){return $.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?A(a,$.ajaxSettings):(b=a,a=$.ajaxSettings),A(a,b),a},ajaxSettings:{url:xc,isLocal:Bc.test(yc[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Lc},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":$.parseJSON,"text xml":$.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:y(Jc),ajaxTransport:y(Kc),ajax:function(a,c){function d(a,c,d,g){var j,l,s,t,v,x=c;2!==u&&(u=2,i&&clearTimeout(i),h=b,f=g||"",w.readyState=a>0?4:0,d&&(t=B(m,w,d)),a>=200&&300>a||304===a?(m.ifModified&&(v=w.getResponseHeader("Last-Modified"),v&&($.lastModified[e]=v),v=w.getResponseHeader("Etag"),v&&($.etag[e]=v)),304===a?(x="notmodified",j=!0):(j=C(m,t),x=j.state,l=j.data,s=j.error,j=!s)):(s=x,(!x||a)&&(x="error",0>a&&(a=0))),w.status=a,w.statusText=""+(c||x),j?p.resolveWith(n,[l,x,w]):p.rejectWith(n,[w,x,s]),w.statusCode(r),r=b,k&&o.trigger("ajax"+(j?"Success":"Error"),[w,m,j?l:s]),q.fireWith(n,[w,x]),k&&(o.trigger("ajaxComplete",[w,m]),--$.active||$.event.trigger("ajaxStop")))}"object"==typeof a&&(c=a,a=b),c=c||{};var e,f,g,h,i,j,k,l,m=$.ajaxSetup({},c),n=m.context||m,o=n!==m&&(n.nodeType||n instanceof $)?$(n):$.event,p=$.Deferred(),q=$.Callbacks("once memory"),r=m.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,setRequestHeader:function(a,b){if(!u){var c=a.toLowerCase();a=t[c]=t[c]||a,s[a]=b}return this},getAllResponseHeaders:function(){return 2===u?f:null},getResponseHeader:function(a){var c;if(2===u){if(!g)for(g={};c=Ac.exec(f);)g[c[1].toLowerCase()]=c[2];c=g[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return u||(m.mimeType=a),this},abort:function(a){return a=a||v,h&&h.abort(a),d(0,a),this}};if(p.promise(w),w.success=w.done,w.error=w.fail,w.complete=q.add,w.statusCode=function(a){if(a){var b;if(2>u)for(b in a)r[b]=[r[b],a[b]];else b=a[w.status],w.always(b)}return this},m.url=((a||m.url)+"").replace(zc,"").replace(Dc,yc[1]+"//"),m.dataTypes=$.trim(m.dataType||"*").toLowerCase().split(bb),null==m.crossDomain&&(j=Hc.exec(m.url.toLowerCase()),m.crossDomain=!(!j||j[1]==yc[1]&&j[2]==yc[2]&&(j[3]||("http:"===j[1]?80:443))==(yc[3]||("http:"===yc[1]?80:443)))),m.data&&m.processData&&"string"!=typeof m.data&&(m.data=$.param(m.data,m.traditional)),z(Jc,m,c,w),2===u)return w;if(k=m.global,m.type=m.type.toUpperCase(),m.hasContent=!Cc.test(m.type),k&&0===$.active++&&$.event.trigger("ajaxStart"),!m.hasContent&&(m.data&&(m.url+=(Ec.test(m.url)?"&":"?")+m.data,delete m.data),e=m.url,m.cache===!1)){var x=$.now(),y=m.url.replace(Gc,"$1_="+x);m.url=y+(y===m.url?(Ec.test(m.url)?"&":"?")+"_="+x:"")}(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",m.contentType),m.ifModified&&(e=e||m.url,$.lastModified[e]&&w.setRequestHeader("If-Modified-Since",$.lastModified[e]),$.etag[e]&&w.setRequestHeader("If-None-Match",$.etag[e])),w.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+Lc+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)w.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(n,w,m)===!1||2===u))return w.abort();v="abort";for(l in{success:1,error:1,complete:1})w[l](m[l]);if(h=z(Kc,m,c,w)){w.readyState=1,k&&o.trigger("ajaxSend",[w,m]),m.async&&m.timeout>0&&(i=setTimeout(function(){w.abort("timeout")},m.timeout));try{u=1,h.send(s,d)}catch(A){if(!(2>u))throw A;d(-1,A)}}else d(-1,"No Transport");return w},active:0,lastModified:{},etag:{}});var Nc=[],Oc=/\?/,Pc=/(=)\?(?=&|$)|\?\?/,Qc=$.now();$.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Nc.pop()||$.expando+"_"+Qc++;return this[a]=!0,a}}),$.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&Pc.test(j),m=k&&!l&&"string"==typeof i&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&Pc.test(i);return"jsonp"===c.dataTypes[0]||l||m?(f=c.jsonpCallback=$.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(Pc,"$1"+f):m?c.data=i.replace(Pc,"$1"+f):k&&(c.url+=(Oc.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||$.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,Nc.push(f)),h&&$.isFunction(g)&&g(h[0]),h=g=b}),"script"):void 0}),$.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return $.globalEval(a),a}}}),$.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),$.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=P.head||P.getElementsByTagName("head")[0]||P.documentElement;return{send:function(e,f){c=P.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){(e||!c.readyState||/loaded|complete/.test(c.readyState))&&(c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||f(200,"success"))},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var Rc,Sc=a.ActiveXObject?function(){for(var a in Rc)Rc[a](0,1)}:!1,Tc=0;$.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&D()||E()}:D,function(a){$.extend($.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}($.ajaxSettings.xhr()),$.support.ajax&&$.ajaxTransport(function(c){if(!c.crossDomain||$.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();if(c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async),c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),c.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||4===i.readyState))if(d=b,g&&(i.onreadystatechange=$.noop,Sc&&delete Rc[g]),e)4!==i.readyState&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}h||!c.isLocal||c.crossDomain?1223===h&&(h=204):h=l.text?200:404}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?4===i.readyState?setTimeout(d,0):(g=++Tc,Sc&&(Rc||(Rc={},$(a).unload(Sc)),Rc[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var Uc,Vc,Wc=/^(?:toggle|show|hide)$/,Xc=new RegExp("^(?:([-+])=|)("+_+")([a-z%]*)$","i"),Yc=/queueHooks$/,Zc=[J],$c={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=Xc.exec(b),h=f.cur(),i=+h||0,j=1;if(g){if(c=+g[2],d=g[3]||($.cssNumber[a]?"":"px"),"px"!==d&&i){i=$.css(f.elem,a,!0)||c||1;do e=j=j||".5",i/=j,$.style(f.elem,a,i+d),j=f.cur()/h;while(1!==j&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};$.Animation=$.extend(H,{tweener:function(a,b){$.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],$c[c]=$c[c]||[],$c[c].unshift(b)},prefilter:function(a,b){b?Zc.unshift(a):Zc.push(a)}}),$.Tween=K,K.prototype={constructor:K,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||($.cssNumber[c]?"":"px")},cur:function(){var a=K.propHooks[this.prop];return a&&a.get?a.get(this):K.propHooks._default.get(this)},run:function(a){var b,c=K.propHooks[this.prop];return this.pos=b=$.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration),this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):K.propHooks._default.set(this),this}},K.prototype.init.prototype=K.prototype,K.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=$.css(a.elem,a.prop,!1,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){$.fx.step[a.prop]?$.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[$.cssProps[a.prop]]||$.cssHooks[a.prop])?$.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},K.propHooks.scrollTop=K.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},$.each(["toggle","show","hide"],function(a,b){var c=$.fn[b];$.fn[b]=function(d,e,f){return null==d||"boolean"==typeof d||!a&&$.isFunction(d)&&$.isFunction(e)?c.apply(this,arguments):this.animate(L(b,!0),d,e,f)}}),$.fn.extend({fadeTo:function(a,b,c,d){return this.filter(r).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=$.isEmptyObject(a),f=$.speed(b,c,d),g=function(){var b=H(this,$.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return"string"!=typeof a&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=null!=a&&a+"queueHooks",f=$.timers,g=$._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&Yc.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem!==this||null!=a&&f[c].queue!==a||(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&$.dequeue(this,a)})}}),$.each({slideDown:L("show"),slideUp:L("hide"),slideToggle:L("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){$.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),$.speed=function(a,b,c){var d=a&&"object"==typeof a?$.extend({},a):{complete:c||!c&&b||$.isFunction(a)&&a,duration:a,easing:c&&b||b&&!$.isFunction(b)&&b};return d.duration=$.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in $.fx.speeds?$.fx.speeds[d.duration]:$.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){$.isFunction(d.old)&&d.old.call(this),d.queue&&$.dequeue(this,d.queue)},d},$.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},$.timers=[],$.fx=K.prototype.init,$.fx.tick=function(){for(var a,b=$.timers,c=0;c-1,l={},m={};k?(m=g.position(),e=m.top,f=m.left):(e=parseFloat(i)||0,f=parseFloat(j)||0),$.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(l.top=b.top-h.top+e),null!=b.left&&(l.left=b.left-h.left+f),"using"in b?b.using.call(a,l):g.css(l)}},$.fn.extend({position:function(){if(this[0]){var a=this[0],b=this.offsetParent(),c=this.offset(),d=_c.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat($.css(a,"marginTop"))||0,c.left-=parseFloat($.css(a,"marginLeft"))||0,d.top+=parseFloat($.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat($.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||P.body;a&&!_c.test(a.nodeName)&&"static"===$.css(a,"position");)a=a.offsetParent;return a||P.body})}}),$.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);$.fn[a]=function(e){return $.access(this,function(a,e,f){var g=M(a);return f===b?g?c in g?g[c]:g.document.documentElement[e]:a[e]:void(g?g.scrollTo(d?$(g).scrollLeft():f,d?f:$(g).scrollTop()):a[e]=f)},a,e,arguments.length,null)}}),$.each({Height:"height",Width:"width"},function(a,c){$.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){$.fn[e]=function(e,f){var g=arguments.length&&(d||"boolean"!=typeof e),h=d||(e===!0||f===!0?"margin":"border");return $.access(this,function(c,d,e){var f;return $.isWindow(c)?c.document.documentElement["client"+a]:9===c.nodeType?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?$.css(c,d,e,h):$.style(c,d,e,h)},c,g?e:b,g)}})}),a.jQuery=a.$=$,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return $})}(window),function(a,b){function c(b,c){var e,f,g,h=b.nodeName.toLowerCase();return"area"===h?(e=b.parentNode,f=e.name,b.href&&f&&"map"===e.nodeName.toLowerCase()?(g=a("img[usemap=#"+f+"]")[0],!!g&&d(g)):!1):(/input|select|textarea|button|object/.test(h)?!b.disabled:"a"===h?b.href||c:c)&&d(b)}function d(b){return a.expr.filters.visible(b)&&!a(b).parents().addBack().filter(function(){return"hidden"===a.css(this,"visibility")}).length}var e=0,f=/^ui-id-\d+$/;a.ui=a.ui||{},a.extend(a.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),a.fn.extend({focus:function(b){return function(c,d){return"number"==typeof c?this.each(function(){var b=this;setTimeout(function(){a(b).focus(),d&&d.call(b)},c)}):b.apply(this,arguments)}}(a.fn.focus),scrollParent:function(){var b;return b=a.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.css(this,"position"))&&/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.css(this,"overflow")+a.css(this,"overflow-y")+a.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length)for(var d,e,f=a(this[0]);f.length&&f[0]!==document;){if(d=f.css("position"),("absolute"===d||"relative"===d||"fixed"===d)&&(e=parseInt(f.css("zIndex"),10),!isNaN(e)&&0!==e))return e;f=f.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})},removeUniqueId:function(){return this.each(function(){f.test(this.id)&&a(this).removeAttr("id")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function e(b,c,d,e){return a.each(f,function(){c-=parseFloat(a.css(b,"padding"+this))||0,d&&(c-=parseFloat(a.css(b,"border"+this+"Width"))||0),e&&(c-=parseFloat(a.css(b,"margin"+this))||0)}),c}var f="Width"===d?["Left","Right"]:["Top","Bottom"],g=d.toLowerCase(),h={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?h["inner"+d].call(this):this.each(function(){a(this).css(g,e(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return"number"!=typeof b?h["outer"+d].call(this,b):this.each(function(){a(this).css(g,e(this,b,!0,c)+"px")})}}),a.fn.addBack||(a.fn.addBack=function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}),a("").data("a-b","a").removeData("a-b").data("a-b")&&(a.fn.removeData=function(b){return function(c){return arguments.length?b.call(this,a.camelCase(c)):b.call(this)}}(a.fn.removeData)),a.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),a.support.selectstart="onselectstart"in document.createElement("div"),a.fn.extend({disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e,f=a.ui[b].prototype;for(e in d)f.plugins[e]=f.plugins[e]||[],f.plugins[e].push([c,d[e]])},call:function(a,b,c){var d,e=a.plugins[b];if(e&&a.element[0].parentNode&&11!==a.element[0].parentNode.nodeType)for(d=0;d0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)}})}(jQuery),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i={},j=b.split(".")[0]; -b=b.split(".")[1],e=j+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[j]=a[j]||{},f=a[j][b],g=a[j][b]=function(a,b){return this._createWidget?void(arguments.length&&this._createWidget(a,b)):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,d){return a.isFunction(d)?void(i[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},e=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=e,b=d.apply(this,arguments),this._super=c,this._superApply=f,b}}()):void(i[b]=d)}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},i,{constructor:g,namespace:j,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasOwnProperty(e)&&f!==b&&(c[e]=a.isPlainObject(f)?a.isPlainObject(c[e])?a.widget.extend({},c[e],f):a.widget.extend({},f):f);return c},a.widget.bridge=function(c,e){var f=e.prototype.widgetFullName||c;a.fn[c]=function(g){var h="string"==typeof g,i=d.call(arguments,1),j=this;return g=!h&&i.length?a.widget.extend.apply(null,[g].concat(i)):g,this.each(h?function(){var d,e=a.data(this,f);return e?a.isFunction(e[g])&&"_"!==g.charAt(0)?(d=e[g].apply(e,i),d!==e&&d!==b?(j=d&&d.jquery?j.pushStack(d.get()):d,!1):void 0):a.error("no such method '"+g+"' for "+c+" widget instance"):a.error("cannot call methods on "+c+" prior to initialization; attempted to call method '"+g+"'")}:function(){var b=a.data(this,f);b?b.option(g||{})._init():a.data(this,f,new e(g,this))}),j}},a.Widget=function(){},a.Widget._childConstructors=[],a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
        ",options:{disabled:!1,create:null},_createWidget:function(b,d){d=a(d||this.defaultElement||this)[0],this.element=a(d),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),d!==this&&(a.data(d,this.widgetFullName,this),this._on(!0,this.element,{remove:function(a){a.target===d&&this.destroy()}}),this.document=a(d.style?d.ownerDocument:d.document||d),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:a.noop,_getCreateEventData:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(a.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e,f,g,h=c;if(0===arguments.length)return a.widget.extend({},this.options);if("string"==typeof c)if(h={},e=c.split("."),c=e.shift(),e.length){for(f=h[c]=a.widget.extend({},this.options[c]),g=0;g=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(a){function b(a,b,c){return a>b&&b+c>a}function c(a){return/left|right/.test(a.css("float"))||/inline|table-cell/.test(a.css("display"))}a.widget("ui.sortable",a.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===a.axis||c(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){"disabled"===b?(this.options[b]=c,this.widget().toggleClass("ui-sortable-disabled",!!c)):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=null,e=!1,f=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(b),a(b.target).parents().each(function(){return a.data(this,f.widgetName+"-item")===f?(d=a(this),!1):void 0}),a.data(b.target,f.widgetName+"-item")===f&&(d=a(b.target)),d&&(!this.options.handle||c||(a(this.options.handle,d).find("*").addBack().each(function(){this===b.target&&(e=!0)}),e))?(this.currentItem=d,this._removeCurrentsFromItems(),!0):!1)},_mouseStart:function(b,c,d){var e,f,g=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,g.cursorAt&&this._adjustOffsetFromHelper(g.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),g.containment&&this._setContainment(),g.cursor&&"auto"!==g.cursor&&(f=this.document.find("body"),this.storedCursor=f.css("cursor"),f.css("cursor",g.cursor),this.storedStylesheet=a("").appendTo(f)),g.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",g.opacity)),g.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",g.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!d)for(e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("activate",b,this._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!g.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){var c,d,e,f,g=this.options,h=!1;for(this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;c--)if(d=this.items[c],e=d.item[0],f=this._intersectsWithPointer(d),f&&d.instance===this.currentContainer&&e!==this.currentItem[0]&&this.placeholder[1===f?"next":"prev"]()[0]!==e&&!a.contains(this.placeholder[0],e)&&("semi-dynamic"===this.options.type?!a.contains(this.element[0],e):!0)){if(this.direction=1===f?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(d))break;this._rearrange(b,d),this._trigger("change",b,this._uiHash());break}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(b){if(a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b),this.options.revert){var d=this,e=this.placeholder.offset(),f=this.options.axis,g={};f&&"x"!==f||(g.left=e.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),f&&"y"!==f||(g.top=e.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,a(this.helper).animate(g,parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--)this.containers[b]._trigger("deactivate",null,this._uiHash(this)),this.containers[b].containerCache.over&&(this.containers[b]._trigger("out",null,this._uiHash(this)),this.containers[b].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[\-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l="x"===this.options.axis||d+j>h&&i>d+j,m="y"===this.options.axis||b+k>f&&g>b+k,n=l&&m;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?n:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return 0!==a&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor===String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c,d,e,f,g=[],h=[],i=this._connectWith();if(i&&b)for(c=i.length-1;c>=0;c--)for(e=a(i[c]),d=e.length-1;d>=0;d--)f=a.data(e[d],this.widgetFullName),f&&f!==this&&!f.options.disabled&&h.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),f]);for(h.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),c=h.length-1;c>=0;c--)h[c][0].each(function(){g.push(this)});return a(g)},_removeCurrentsFromItems:function(){var b=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=a.grep(this.items,function(a){for(var c=0;c=0;c--)for(e=a(m[c]),d=e.length-1;d>=0;d--)f=a.data(e[d],this.widgetFullName),f&&f!==this&&!f.options.disabled&&(l.push([a.isFunction(f.options.items)?f.options.items.call(f.element[0],b,{item:this.currentItem}):a(f.options.items,f.element),f]),this.containers.push(f));for(c=l.length-1;c>=0;c--)for(g=l[c][1],h=l[c][0],d=0,j=h.length;j>d;d++)i=a(h[d]),i.data(this.widgetName+"-item",g),k.push({item:i,instance:g,width:0,height:0,left:0,top:0})},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var c,d,e,f;for(c=this.items.length-1;c>=0;c--)d=this.items[c],d.instance!==this.currentContainer&&this.currentContainer&&d.item[0]!==this.currentItem[0]||(e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item,b||(d.width=e.outerWidth(),d.height=e.outerHeight()),f=e.offset(),d.left=f.left,d.top=f.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(c=this.containers.length-1;c>=0;c--)f=this.containers[c].element.offset(),this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight();return this},_createPlaceholder:function(b){b=b||this;var c,d=b.options;d.placeholder&&d.placeholder.constructor!==String||(c=d.placeholder,d.placeholder={element:function(){var d=b.currentItem[0].nodeName.toLowerCase(),e=a("<"+d+">",b.document[0]).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===d?b.currentItem.children().each(function(){a("
        ",b.document[0]).attr("colspan",a(this).attr("colspan")||1).appendTo(e)}):"img"===d&&e.attr("src",b.currentItem.attr("src")),c||e.css("visibility","hidden"),e},update:function(a,e){(!c||d.forcePlaceholderSize)&&(e.height()||e.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10)),e.width()||e.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10)))}}),b.placeholder=a(d.placeholder.element.call(b.element,b.currentItem)),b.currentItem.after(b.placeholder),d.placeholder.update(b,b.placeholder)},_contactContainers:function(d){var e,f,g,h,i,j,k,l,m,n,o=null,p=null;for(e=this.containers.length-1;e>=0;e--)if(!a.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(o&&a.contains(this.containers[e].element[0],o.element[0]))continue;o=this.containers[e],p=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",d,this._uiHash(this)),this.containers[e].containerCache.over=0);if(o)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",d,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(g=1e4,h=null,n=o.floating||c(this.currentItem),i=n?"left":"top",j=n?"width":"height",k=this.positionAbs[i]+this.offset.click[i],f=this.items.length-1;f>=0;f--)a.contains(this.containers[p].element[0],this.items[f].item[0])&&this.items[f].item[0]!==this.currentItem[0]&&(!n||b(this.positionAbs.top+this.offset.click.top,this.items[f].top,this.items[f].height))&&(l=this.items[f].item.offset()[i],m=!1,Math.abs(l-k)>Math.abs(l+this.items[f][j]-k)&&(m=!0,l+=this.items[f][j]),Math.abs(l-k)this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top)),e.grid&&(c=this.originalPageY+Math.round((g-this.originalPageY)/e.grid[1])*e.grid[1],g=this.containment?c-this.offset.click.top>=this.containment[1]&&c-this.offset.click.top<=this.containment[3]?c:c-this.offset.click.top>=this.containment[1]?c-e.grid[1]:c+e.grid[1]:c,d=this.originalPageX+Math.round((f-this.originalPageX)/e.grid[0])*e.grid[0],f=this.containment?d-this.offset.click.left>=this.containment[0]&&d-this.offset.click.left<=this.containment[2]?d:d-this.offset.click.left>=this.containment[0]?d-e.grid[0]:d+e.grid[0]:d)),{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():i?0:h.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():i?0:h.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this.counter;this._delay(function(){e===this.counter&&this.refreshPositions(!d)})},_clear:function(a,b){this.reverting=!1;var c,d=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(c in this._storedCSS)("auto"===this._storedCSS[c]||"static"===this._storedCSS[c])&&(this._storedCSS[c]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!b&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||b||d.push(function(a){this._trigger("update",a,this._uiHash())}),this!==this.currentContainer&&(b||(d.push(function(a){this._trigger("remove",a,this._uiHash())}),d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.currentContainer)),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.currentContainer)))),c=this.containers.length-1;c>=0;c--)b||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[c])),this.containers[c].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[c])),this.containers[c].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!b){for(this._trigger("beforeStop",a,this._uiHash()),c=0;c
        ',trigger:"hover",title:"",delay:0,html:!0}}(window.jQuery);var Constants={DEFAULT:{HEIGHT:32,WIDTH:32,FPS:12},MODEL_VERSION:2,MAX_HEIGHT:1024,MAX_WIDTH:1024,MAX_CURRENT_COLORS_DISPLAYED:100,MINIMUM_ZOOM:1,PREVIEW_FILM_SIZE:96,ANIMATED_PREVIEW_WIDTH:200,DEFAULT_PEN_COLOR:"#000000",TRANSPARENT_COLOR:"rgba(0, 0, 0, 0)",OVERLAY_ONION_SKIN:"onion-skin",OVERLAY_LAYER_PREVIEW:"layer-preview",OVERLAY_DISABLED:"no-overlay",NO_PALETTE_ID:"__no-palette",CURRENT_COLORS_PALETTE_ID:"__current-colors",PREFERRED_COLOR_FORMAT:"rgb",SELECTION_TRANSPARENT_COLOR:"rgba(255, 255, 255, 0.6)",TOOL_TARGET_HIGHLIGHT_COLOR:"rgba(255, 255, 255, 0.2)",STATIC:{URL:{SAVE:"http://3.piskel-app.appspot.com/store",GET:"http://3.piskel-app.appspot.com/get"}},APPENGINE:{URL:{SAVE:"save"}},IMAGE_SERVICE_UPLOAD_URL:"http://piskel-imgstore-a.appspot.com/__/upload",IMAGE_SERVICE_GET_URL:"http://piskel-imgstore-a.appspot.com/img/",ZOOMED_OUT_BACKGROUND_COLOR:"#A0A0A0",LEFT_BUTTON:0,MIDDLE_BUTTON:1,RIGHT_BUTTON:2,MOUSEMOVE_THROTTLING:10,ABSTRACT_FUNCTION:function(){throw"abstract method should be implemented"},EMPTY_FUNCTION:function(){},DRAWING_TEST_FOLDER:"drawing"},Events={TOOL_SELECTED:"TOOL_SELECTED",SELECT_TOOL:"SELECT_TOOL",TOOL_RELEASED:"TOOL_RELEASED",SELECT_PRIMARY_COLOR:"SELECT_PRIMARY_COLOR",SELECT_SECONDARY_COLOR:"SELECT_SECONDARY_COLOR",PRIMARY_COLOR_SELECTED:"PRIMARY_COLOR_SELECTED",SECONDARY_COLOR_SELECTED:"SECONDARY_COLOR_SELECTED",CURSOR_MOVED:"CURSOR_MOVED",DRAG_START:"DRAG_START",DRAG_END:"DRAG_END",DIALOG_DISPLAY:"DIALOG_DISPLAY",DIALOG_HIDE:"DIALOG_HIDE",PALETTE_LIST_UPDATED:"PALETTE_LIST_UPDATED",USER_SETTINGS_CHANGED:"USER_SETTINGS_CHANGED",CLOSE_SETTINGS_DRAWER:"CLOSE_SETTINGS_DRAWER",PISKEL_RESET:"PISKEL_RESET",PISKEL_SAVE_STATE:"PISKEL_SAVE_STATE",PISKEL_SAVED:"PISKEL_SAVED",FRAME_SIZE_CHANGED:"FRAME_SIZE_CHANGED",SELECTION_CREATED:"SELECTION_CREATED",SELECTION_MOVE_REQUEST:"SELECTION_MOVE_REQUEST",SELECTION_DISMISSED:"SELECTION_DISMISSED",SHOW_NOTIFICATION:"SHOW_NOTIFICATION",HIDE_NOTIFICATION:"HIDE_NOTIFICATION",ZOOM_CHANGED:"ZOOM_CHANGED",CURRENT_COLORS_UPDATED:"CURRENT_COLORS_UPDATED",MOUSE_EVENT:"MOUSE_EVENT",TEST_RECORD_END:"TEST_RECORD_END",TEST_CASE_END:"TEST_CASE_END",TEST_SUITE_END:"TEST_SUITE_END"};jQuery.namespace=function(){var a,b,c,d=arguments,e=null;for(a=0;a255||b>255||c>255)throw"Invalid color component";return(a<<16|b<<8|c).toString(16)},a.normalize=function(a,b){return"undefined"==typeof a||null===a?b:a},a.inherit=function(a,b){a.prototype=Object.create(b.prototype),a.prototype.constructor=a,a.prototype.superclass=b.prototype},a.wrap=function(a,b){for(var c in b)"function"==typeof b[c]&&"undefined"==typeof a[c]&&(a[c]=b[c].bind(b))};var b={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};a.escapeHtml=function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return b[a]})};var c={};a.unescapeHtml=function(a){return Object.keys(b).forEach(function(d){c[d]=c[d]||new RegExp(b[d],"g"),a=a.replace(c[d],d)}),a}}(),function(){var a=$.namespace("pskl.utils"),b=navigator.userAgent;a.UserAgent={isIE:/MSIE/i.test(b),isIE11:/trident/i.test(b),isChrome:/Chrome/i.test(b),isFirefox:/Firefox/i.test(b),isMac:/Mac/.test(b)},a.UserAgent.version=function(){return pskl.utils.UserAgent.isIE?parseInt(/MSIE\s?(\d+)/i.exec(b)[1],10):pskl.utils.UserAgent.isChrome?parseInt(/Chrome\/(\d+)/i.exec(b)[1],10):pskl.utils.UserAgent.isFirefox?parseInt(/Firefox\/(\d+)/i.exec(b)[1],10):void 0}()}(),function(){var a,b=$.namespace("pskl.utils");Uint8Array&&(a=new Uint8Array([62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,0,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51])),b.Base64={toText:function(a){return window.atob(a.replace(/data\:.*?\;base64\,/,""))},decode:function(b){for(var c,d=0,e=[0,0],f=0,g=0,h=b.length,i=0,j=new Uint8Array(h/4*3|0);h--;){var k=b.charCodeAt(i++),l=a[k-43];255!==l&&l!==c&&(e[1]=e[0],e[0]=k,g=g<<6|l,f++,4===f&&(j[d++]=g>>>16,61!==e[1]&&(j[d++]=g>>>8),61!==e[0]&&(j[d++]=g),f=0))}return j.buffer}}}(),function(){var a=$.namespace("pskl.utils"),b=/\s*;\s*base64\s*(?:;|$)/i;a.BlobUtils={dataToBlob:function(a,c,d){var e,f=a.indexOf(","),g=a.substring(f+1),h=b.test(a.substring(0,f));if(Blob.fake)e=new Blob,e.encoding=h?"base64":"URI",e.data=g,e.size=g.length;else if(Uint8Array){var i=h?pskl.utils.Base64.decode(g):decodeURIComponent(g);e=new Blob([i],{type:c})}d(e)},canvasToBlob:function(a,b,c){if(c=c||"image/png",a.mozGetAsFile)b(a.mozGetAsFile("canvas",c));else{var d=Array.prototype.slice.call(arguments,2),e=a.toDataURL.apply(a,d);pskl.utils.BlobUtils.dataToBlob(e,c,b)}},stringToBlob:function(a,b,c){c=c||"text/plain",pskl.utils.BlobUtils.dataToBlob("data:"+c+","+a,c,b)}}}(),function(){var a=$.namespace("pskl");a.CanvasUtils={createCanvas:function(a,b,c){var d=document.createElement("canvas");if(d.setAttribute("width",a),d.setAttribute("height",b),"string"==typeof c&&(c=[c]),Array.isArray(c))for(var e=0;ea?"0"+a:""+a};a.DateUtils={format:function(a,c){return a=new Date(a),pskl.utils.Template.replace(c,{Y:a.getFullYear(),M:b(a.getMonth()+1),D:b(a.getDate()),H:b(a.getHours()),m:b(a.getMinutes()),s:b(a.getSeconds())})}}}(),function(){var a=$.namespace("pskl.utils");a.Dom={isParent:function(a,b,c){if(a&&b)for(c&&(a=a.parentNode);a;){if(a===b)return!0;a=a.parentNode}return!1},getParentWithData:function(a,b){for(;a;){if(a.dataset&&"undefined"!=typeof a.dataset[b])return a;a=a.parentNode}return null}}}(),function(){var a=$.namespace("pskl.utils");a.Math={minmax:function(a,b,c){return Math.max(Math.min(a,c),b)}}}(),function(){var a=$.namespace("pskl.utils"),b=function(a){a.stopPropagation()};a.FileUtils={readFile:function(a,b){var c=new FileReader;c.onload=function(a){b(a.target.result)},c.readAsDataURL(a)},readImageFile:function(b,c){a.FileUtils.readFile(b,function(a){var b=new Image;b.onload=c.bind(null,b),b.src=a})},downloadAsFile:function(a,c){var d=window.saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator);if(d)d(a,c);else{var e=document.createElement("a");a=window.URL.createObjectURL(a),e.setAttribute("href",a),e.setAttribute("download",c),document.body.appendChild(e),e.addEventListener("click",b),e.click(),e.removeEventListener("click",b),document.body.removeChild(e)}}}}(),function(){var a=$.namespace("pskl.utils"),b={};a.FrameUtils={merge:function(a){var b=null;if(a.length){b=a[0].clone();for(var c=(b.getWidth(),b.getHeight(),1);ce;e++){d[e]=[];for(var f=0;c>f;f++){var g=4*(f*b+e),h=a[g],i=a[g+1],j=a[g+2],k=a[g+3];d[e][f]=125>k?Constants.TRANSPARENT_COLOR:pskl.utils.FrameUtils.rgbToHex(h,i,j)}}return pskl.model.Frame.fromPixelGrid(d)},rgbToHex:function(a,b,c){return"#"+this.componentToHex(a)+this.componentToHex(b)+this.componentToHex(c)},componentToHex:function(a){var b=a.toString(16);return 1==b.length?"0"+b:b},toImage:function(a,b,c){b=b||1,c=c||Constants.TRANSPARENT_COLOR;var d=new pskl.rendering.CanvasRenderer(a,b);return d.drawTransparentAs(c),d.render()}}}(),function(){var a=$.namespace("pskl.utils");a.LayerUtils={createFromImage:function(a,b){var c=a.width,d=a.height,e=c/b,f=pskl.CanvasUtils.createCanvas(c,d),g=f.getContext("2d");g.drawImage(a,0,0,c,d,0,0,c,d);for(var h=[],i=0;b>i;i++){var j=g.getImageData(e*i,0,e,d).data,k=pskl.utils.FrameUtils.createFromImageData(j,e,d);h.push(k)}return h}}}(),function(){var a=$.namespace("pskl.utils");a.ImageResizer={resize:function(a,b,c,d){var e=pskl.CanvasUtils.createCanvas(b,c),f=e.getContext("2d");return f.save(),d||pskl.CanvasUtils.disableImageSmoothing(e),f.translate(e.width/2,e.height/2),f.scale(b/a.width,c/a.height),f.drawImage(a,-a.width/2,-a.height/2),f.restore(),e},resizeNearestNeighbour:function(a,b,c,d){c=c||0;for(var e,f,g=pskl.CanvasUtils.createCanvas(b*a.width,b*a.height),h=g.getContext("2d"),i=pskl.CanvasUtils.getImageDataFromCanvas(a),j={},k=0,l=0,m=0;m0;){k++;var m=g.pop();a.setPixel(m.col,m.row,d),f.push({col:m.col,row:m.row});for(var n=0;4>n;n++){var o=m.col+i[n],p=m.row+h[n];try{a.containsPixel(o,p)&&a.getPixel(o,p)==e&&g.push({col:o,row:p})}catch(j){}}if(k>10*l){console.log("loop breaker called");break}}return f}},calculateZoomForContainer:function(a,b,c){return this.calculateZoom(a.height(),a.width(),b,c)}}}(),function(){var a=$.namespace("pskl.utils");a.PiskelFileUtils={loadFromFile:function(a,b){pskl.utils.FileUtils.readFile(a,function(a){var c=pskl.utils.Base64.toText(a),d=JSON.parse(c),e=d.piskel.fps,f=new pskl.model.piskel.Descriptor(d.piskel.name,d.piskel.description,!0);pskl.utils.serialization.Deserializer.deserialize(d,function(a){b(a,f,e)})})}}}(),function(){var a=$.namespace("pskl.utils"),b={};a.Template={get:function(a){if(!b[a]){var c=document.getElementById(a);c?b[a]=c.innerHTML:console.error("Could not find template for id :",a)}return b[a]},createFromHTML:function(a){var b=document.createElement("div");return b.innerHTML=a,b.children[0]},getAndReplace:function(a,b){var c="",d=pskl.utils.Template.get(a);return d&&(c=pskl.utils.Template.replace(d,b)),c},replace:function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=b[c];-1!==c.indexOf(":")&&(d===!0?d=c.split(":")[1]:d===!1&&(d="")),a=a.replace(new RegExp("\\{\\{"+c+"\\}\\}","g"),d)}return a}}}(),function(){var a=$.namespace("pskl");a.UserSettings={GRID_WIDTH:"GRID_WIDTH",CANVAS_BACKGROUND:"CANVAS_BACKGROUND",SELECTED_PALETTE:"SELECTED_PALETTE",TILED_PREVIEW:"TILED_PREVIEW",ONION_SKIN:"ONION_SKIN",LAYER_PREVIEW:"LAYER_PREVIEW",KEY_TO_DEFAULT_VALUE_MAP_:{GRID_WIDTH:0,CANVAS_BACKGROUND:"lowcont-dark-canvas-background",SELECTED_PALETTE:Constants.CURRENT_COLORS_PALETTE_ID,TILED_PREVIEW:!1,ONION_SKIN:!1,LAYER_PREVIEW:!0},cache_:{},get:function(a){if(this.checkKeyValidity_(a),!(a in this.cache_)){var b=this.readFromLocalStorage_(a);this.cache_[a]="undefined"!=typeof b&&null!==b?b:this.readFromDefaults_(a)}return this.cache_[a]},set:function(a,b){this.checkKeyValidity_(a),this.cache_[a]=b,this.writeToLocalStorage_(a,b),$.publish(Events.USER_SETTINGS_CHANGED,[a,b])},readFromLocalStorage_:function(a){var b=window.localStorage[a];return"undefined"!=typeof b&&(b=JSON.parse(b)),b},writeToLocalStorage_:function(a,b){window.localStorage[a]=JSON.stringify(b)},readFromDefaults_:function(a){return this.KEY_TO_DEFAULT_VALUE_MAP_[a]},checkKeyValidity_:function(a){a in this.KEY_TO_DEFAULT_VALUE_MAP_||console.log("UserSettings key <"+a+"> not find in supported keys.")}}}(),function(){var a=$.namespace("pskl.utils"),b=function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)};a.Uuid={generate:function(){return"ss-s-s-s-sss".replace(/s/g,function(){return b()})}}}(),function(){var a=$.namespace("pskl.utils");a.Xhr={get:function(b,c,d){var e=a.Xhr.xhr_(b,"GET",c,d);e.send()},post:function(b,c,d,e){var f=a.Xhr.xhr_(b,"POST",d,e),g=new FormData;if("object"==typeof c)for(var h in c)c.hasOwnProperty(h)&&g.append(h,c[h]);f.send(g)},xhr_:function(a,b,c,d){c=c||function(){},d=d||function(){};var e=new XMLHttpRequest;return e.open(b,a,!0),e.onload=function(a){200==this.status?c(this):this.onerror(this,a)},e.onerror=function(a){d(a)},e}}}(),function(){var a=$.namespace("pskl.utils");a.Serializer={serializePiskel:function(a,b){var c=a.getLayers().map(function(a){return pskl.utils.Serializer.serializeLayer(a,b)});return JSON.stringify({modelVersion:Constants.MODEL_VERSION,piskel:{name:a.getDescriptor().name,description:a.getDescriptor().description,fps:pskl.app.piskelController.getFPS(),height:a.getHeight(),width:a.getWidth(),layers:c,expanded:b}})},serializeLayer:function(a,b){var c=a.getFrames(),d=new pskl.rendering.FramesheetRenderer(c),e={name:a.getName(),frameCount:c.length};return b?(e.grids=c.map(function(a){return a.pixels}),e):(e.base64PNG=d.renderAsCanvas().toDataURL(),JSON.stringify(e))}}}(),function(){var a=$.namespace("pskl.utils.serialization");a.Deserializer=function(a,b){this.layersToLoad_=0,this.data_=a,this.callback_=b,this.piskel_=null},a.Deserializer.deserialize=function(b,c){var d;d=b.modelVersion==Constants.MODEL_VERSION?new a.Deserializer(b,c):1==b.modelVersion?new a.backward.Deserializer_v1(b,c):new a.backward.Deserializer_v0(b,c),d.deserialize()},a.Deserializer.prototype.deserialize=function(a){var b=this.data_,c=b.piskel;a=a||"Deserialized piskel";var d=new pskl.model.piskel.Descriptor(a,"");this.piskel_=new pskl.model.Piskel(c.width,c.height,d),this.layersToLoad_=c.layers.length,c.layers.forEach(c.expanded?this.loadExpandedLayer.bind(this):this.deserializeLayer.bind(this))},a.Deserializer.prototype.deserializeLayer=function(a){var b=JSON.parse(a),c=new pskl.model.Layer(b.name),d=b.base64PNG,e=new Image;return e.onload=function(){var a=pskl.utils.LayerUtils.createFromImage(e,b.frameCount);this.addFramesToLayer(a,c)}.bind(this),e.src=d,c},a.Deserializer.prototype.loadExpandedLayer=function(a){var b=new pskl.model.Layer(a.name),c=a.grids.map(function(a){return pskl.model.Frame.fromPixelGrid(a)});return this.addFramesToLayer(c,b),b},a.Deserializer.prototype.addFramesToLayer=function(a,b){a.forEach(b.addFrame.bind(b)),this.piskel_.addLayer(b),this.onLayerLoaded_()},a.Deserializer.prototype.onLayerLoaded_=function(){this.layersToLoad_=this.layersToLoad_-1,0===this.layersToLoad_&&this.callback_(this.piskel_)}}(),function(){var a=$.namespace("pskl.utils.serialization.backward");a.Deserializer_v0=function(a,b){this.data_=a,this.callback_=b},a.Deserializer_v0.prototype.deserialize=function(){var a=this.data_,b=a.map(function(a){return pskl.model.Frame.fromPixelGrid(a)}),c=new pskl.model.piskel.Descriptor("Deserialized piskel",""),d=pskl.model.Layer.fromFrames("Layer 1",b);this.callback_(pskl.model.Piskel.fromLayers([d],c))}}(),function(){var a=$.namespace("pskl.utils.serialization.backward");a.Deserializer_v1=function(a,b){this.callback_=b,this.data_=a},a.Deserializer_v1.prototype.deserialize=function(){var a=this.data_.piskel,b=new pskl.model.piskel.Descriptor("Deserialized piskel",""),c=new pskl.model.Piskel(a.width,a.height,b);a.layers.forEach(function(a){var b=this.deserializeLayer(a);c.addLayer(b)}.bind(this)),this.callback_(c)},a.Deserializer_v1.prototype.deserializeLayer=function(a){var b=JSON.parse(a),c=new pskl.model.Layer(b.name);return b.frames.forEach(function(a){var b=this.deserializeFrame(a);c.addFrame(b)}.bind(this)),c},a.Deserializer_v1.prototype.deserializeFrame=function(a){var b=JSON.parse(a);return pskl.model.Frame.fromPixelGrid(b)}}(),function(){var a=function(){(function(){function a(b,c){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var d=a.resolve(b);if(!d)throw new Error("Failed to resolve module "+b);var e={id:b,require:a,filename:b,exports:{},loaded:!1,parent:c,children:[]};c&&c.children.push(e);var f=b.slice(0,b.lastIndexOf("/")+1);return a.cache[b]=e.exports,d.call(e.exports,e,e.exports,f,b),e.loaded=!0,a.cache[b]=e.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define("/gif.worker.coffee",function(b){var c,d;c=a("/GIFEncoder.js",b),d=function(a){var b,d,e,f;return b=new c(a.width,a.height),0===a.index?b.writeHeader():b.firstFrame=!1,b.setTransparent(a.transparent),b.setRepeat(a.repeat),b.setDelay(a.delay),b.setQuality(a.quality),b.setPreserveColors(a.preserveColors),b.addFrame(a.data),a.last&&b.finish(),e=b.stream(),a.data=e.pages,a.cursor=e.cursor,a.pageSize=e.constructor.pageSize,a.canTransfer?(f=function(b){for(var c=0,e=a.data.length;e>c;++c)d=a.data[c],b.push(d.buffer);return b}.call(this,[]),self.postMessage(a,f)):self.postMessage(a)},self.onmessage=function(a){return d(a.data)}}),a.define("/GIFEncoder.js",function(b){function c(){this.page=-1,this.pages=[],this.newPage()}function d(a,b){this.width=~~a,this.height=~~b,this.transparent=null,this.transIndex=0,this.repeat=-1,this.delay=0,this.image=null,this.pixels=null,this.indexedPixels=null,this.colorDepth=null,this.colorTab=null,this.usedEntry=new Array,this.palSize=7,this.dispose=-1,this.firstFrame=!0,this.sample=10,this.preserveColors=!1,this.out=new c}var e=a("/TypedNeuQuant.js",b),f=a("/SimpleQuant.js",b),g=a("/LZWEncoder.js",b);c.pageSize=4096,c.charMap={};for(var h=0;256>h;h++)c.charMap[h]=String.fromCharCode(h);c.prototype.newPage=function(){this.pages[++this.page]=new Uint8Array(c.pageSize),this.cursor=0},c.prototype.getData=function(){for(var a="",b=0;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(a){for(var b=a.length,c=0;b>c;c++)this.writeByte(a.charCodeAt(c))},c.prototype.writeBytes=function(a,b,c){for(var d=c||a.length,e=b||0;d>e;e++)this.writeByte(a[e])},d.prototype.setDelay=function(a){this.delay=Math.round(a/10)},d.prototype.setFrameRate=function(a){this.delay=Math.round(100/a)},d.prototype.setDispose=function(a){a>=0&&(this.dispose=a)},d.prototype.setRepeat=function(a){this.repeat=a},d.prototype.setTransparent=function(a){this.transparent=a},d.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},d.prototype.finish=function(){this.out.writeByte(59)},d.prototype.setQuality=function(a){1>a&&(a=1),this.sample=a},d.prototype.setPreserveColors=function(a){this.preserveColors=a},d.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")},d.prototype.analyzePixels=function(){var a=this.pixels.length,b=a/3;this.indexedPixels=new Uint8Array(b);var c;c=this.preserveColors?new f(this.pixels,this.sample):new e(this.pixels,this.sample),c.buildColormap(),this.colorTab=c.getColormap();for(var d=0,g=0;b>g;g++){var h=c.lookupRGB(255&this.pixels[d++],255&this.pixels[d++],255&this.pixels[d++]);this.usedEntry[h]=!0,this.indexedPixels[g]=h}this.pixels=null,this.colorDepth=8,this.palSize=7,null!==this.transparent&&(this.transIndex=this.findClosest(this.transparent))},d.prototype.findClosest=function(a){if(null===this.colorTab)return-1;for(var b=(16711680&a)>>16,c=(65280&a)>>8,d=255&a,e=0,f=16777216,g=this.colorTab.length,h=0;g>h;){var i=b-(255&this.colorTab[h++]),j=c-(255&this.colorTab[h++]),k=d-(255&this.colorTab[h]),l=i*i+j*j+k*k,m=parseInt(h/3);this.usedEntry[m]&&f>l&&(f=l,e=m),h++}return e},d.prototype.getImagePixels=function(){var a=this.width,b=this.height;this.pixels=new Uint8Array(a*b*3);for(var c=this.image,d=0,e=0;b>e;e++)for(var f=0;a>f;f++){var g=e*a*4+4*f;this.pixels[d++]=c[g],this.pixels[d++]=c[g+1],this.pixels[d++]=c[g+2]}},d.prototype.writeGraphicCtrlExt=function(){this.out.writeByte(33),this.out.writeByte(249),this.out.writeByte(4);var a,b;null===this.transparent?(a=0,b=0):(a=1,b=2),this.dispose>=0&&(b=7&dispose),b<<=2,this.out.writeByte(0|b|0|a),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},d.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(this.firstFrame?0:128|this.palSize)},d.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},d.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes("NETSCAPE2.0"),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},d.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);for(var a=768-this.colorTab.length,b=0;a>b;b++)this.out.writeByte(0)},d.prototype.writeShort=function(a){this.out.writeByte(255&a),this.out.writeByte(a>>8&255)},d.prototype.writePixels=function(){var a=new g(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},d.prototype.stream=function(){return this.out},b.exports=d}),a.define("/LZWEncoder.js",function(a){function b(a,b,g,h){function i(a,b){y[s++]=a,s>=254&&n(b)}function j(a){k(e),C=v+2,D=!0,q(v,a)}function k(a){for(var b=0;a>b;++b)z[b]=-1}function l(a,b){var f,g,h,i,l,m,n;for(u=a,D=!1,n_bits=u,t=o(n_bits),v=1<f;f*=2)++n;n=8-n,m=e,k(m),q(v,b);a:for(;(g=p())!=c;)if(f=(g<=0){l=m-h,0===h&&(l=1);do if((h-=l)<0&&(h+=m),z[h]===f){i=A[h];continue a}while(z[h]>=0)}q(i,b),i=g,1<C?(A[h]=C++,z[h]=f):j(b)}else i=A[h];q(i,b),q(w,b)}function m(c){c.writeByte(x),remaining=a*b,curPixel=0,l(x+1,c),c.writeByte(0)}function n(a){s>0&&(a.writeByte(s),a.writeBytes(y,0,s),s=0)}function o(a){return(1<0?r|=a<=8;)i(255&r,b),r>>=8,B-=8;if((C>t||D)&&(D?(t=o(n_bits=u),D=!1):(++n_bits,t=n_bits==d?1<0;)i(255&r,b),r>>=8,B-=8;n(b)}}var r,s,t,u,v,w,x=Math.max(2,h),y=new Uint8Array(256),z=new Int32Array(e),A=new Int32Array(e),B=0,C=0,D=!1;this.encode=m}var c=-1,d=12,e=5003,f=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];a.exports=b}),a.define("/SimpleQuant.js",function(a){function b(a,b,c){return[a,b,c].join(".")}function c(a){this.pixels=a,this.palette=[],this.paletteIndex={},this.getColormap=function(){return this.palette},this.buildColormap=function(){for(var a=this.pixels.length/3,c=0,d=0;a>d;d++){var e=this.pixels[c++],f=this.pixels[c++],g=this.pixels[c++],h=b(e,f,g);this.paletteIndex[h]||(this.palette.push(e),this.palette.push(f),this.palette.push(g),this.paletteIndex[h]=this.palette.length/3-1)}},this.lookupRGB=function(a,c,d){return this.paletteIndex[b(a,c,d)]}}a.exports=c}),a.define("/TypedNeuQuant.js",function(a){function b(a,b){function m(){H=[],I=new Int32Array(256),J=new Int32Array(d),K=new Int32Array(d),L=new Int32Array(d>>3);var a,b;for(a=0;d>a;a++)b=(a<a;a++)H[a][0]>>=f,H[a][1]>>=f,H[a][2]>>=f,H[a][3]=a}function r(a,b,c,d,e){H[b][0]-=a*(H[b][0]-c)/s,H[b][1]-=a*(H[b][1]-d)/s,H[b][2]-=a*(H[b][2]-e)/s}function t(a,b,c,e,f){for(var g,h,i=Math.abs(b-a),j=Math.min(b+a,d),k=b+1,l=b-1,m=1;j>k||l>i;)h=L[m++],j>k&&(g=H[k++],g[0]-=h*(g[0]-c)/w,g[1]-=h*(g[1]-e)/w,g[2]-=h*(g[2]-f)/w),l>i&&(g=H[l--],g[0]-=h*(g[0]-c)/w,g[1]-=h*(g[1]-e)/w,g[2]-=h*(g[2]-f)/w)}function v(a,b,c){var e,h,m,n,o,p=2147483647,q=p,r=-1,s=r;for(e=0;d>e;e++)h=H[e],m=Math.abs(h[0]-a)+Math.abs(h[1]-b)+Math.abs(h[2]-c),p>m&&(p=m,r=e),n=m-(J[e]>>g-f),q>n&&(q=n,s=e),o=K[e]>>j,K[e]-=o,J[e]+=o<a;a++){for(c=H[a],g=a,h=c[1],b=a+1;d>b;b++)f=H[b],f[1]>1,b=i+1;h>b;b++)I[b]=a;i=h,j=a}}for(I[i]=j+e>>1,b=i+1;256>b;b++)I[b]=e}function D(a,b,c){for(var e,f,g,h=1e3,i=-1,j=I[b],k=j-1;d>j||k>=0;)d>j&&(f=H[j],g=f[1]-b,g>=h?j=d:(j++,0>g&&(g=-g),e=f[0]-a,0>e&&(e=-e),g+=e,h>g&&(e=f[2]-c,0>e&&(e=-e),g+=e,h>g&&(h=g,i=f[3])))),k>=0&&(f=H[k],g=b-f[1],g>=h?k=-1:(k--,0>g&&(g=-g),e=f[0]-a,0>e&&(e=-e),g+=e,h>g&&(e=f[2]-c,0>e&&(e=-e),g+=e,h>g&&(h=g,i=f[3]))));return i}function E(){var d,e=a.length,g=30+(b-1)/3,h=e/(3*b),i=~~(h/c),j=s,k=p,l=k>>n;for(1>=l&&(l=0),d=0;l>d;d++)L[d]=j*((l*l-d*d)*u/(l*l));var m;B>e?(b=1,m=3):m=e%x!==0?3*x:e%y!==0?3*y:e%z!==0?3*z:3*A;var o,w,C,D,E=0;for(d=0;h>d;)if(o=(255&a[E])<=e&&(E-=e),d++,0===i&&(i=1),d%i===0)for(j-=j/g,k-=k/q,l=k>>n,1>=l&&(l=0),D=0;l>D;D++)L[D]=j*((l*l-D*D)*u/(l*l))}function F(){m(),E(),o(),C()}function G(){for(var a=[],b=[],c=0;d>c;c++)b[H[c][3]]=c;for(var e=0,f=0;d>f;f++){var g=b[f];a[e++]=H[g][0],a[e++]=H[g][1],a[e++]=H[g][2]}return a}var H,I,J,K,L;this.buildColormap=F,this.getColormap=G,this.lookupRGB=D}var c=100,d=256,e=d-1,f=4,g=16,h=1<>j,l=h<>3,n=6,o=1<c;++c)if(c in b&&b[c]===a)return!0;return!1}function e(a,b){function d(){this.constructor=a}for(var e in b)c(b,e)&&(a[e]=b[e]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a}var f,g,h,i,j;h=b("events",a).EventEmitter,f=b("/browser.coffee",a),j=function(a){function b(a){var b,c;this.running=!1,this.options={},this.frames=[],this.freeWorkers=[],this.activeWorkers=[],this.setOptions(a);for(b in g)c=g[b],null!=this.options[b]?this.options[b]:this.options[b]=c}return e(b,a),g={workerScript:window.GifWorkerURL,workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null,preserveColors:!1},i={delay:500,copy:!1},b.prototype.setOption=function(a,b){return this.options[a]=b,null==this._canvas||"width"!==a&&"height"!==a?void 0:this._canvas[a]=b},b.prototype.setOptions=function(a){var b,d;return function(e){for(b in a)c(a,b)&&(d=a[b],e.push(this.setOption(b,d)));return e}.call(this,[])},b.prototype.addFrame=function(a,b){var c,d;null==b&&(b={}),c={},c.transparent=this.options.transparent;for(d in i)c[d]=b[d]||i[d];if(null!=this.options.width||this.setOption("width",a.width),null!=this.options.height||this.setOption("height",a.height),"undefined"!=typeof ImageData&&null!=ImageData&&a instanceof ImageData)c.data=a.data;else if("undefined"!=typeof CanvasRenderingContext2D&&null!=CanvasRenderingContext2D&&a instanceof CanvasRenderingContext2D||"undefined"!=typeof WebGLRenderingContext&&null!=WebGLRenderingContext&&a instanceof WebGLRenderingContext)b.copy?c.data=this.getContextData(a):c.context=a;else{if(null==a.childNodes)throw new Error("Invalid image");b.copy?c.data=this.getImageData(a):c.image=a}return this.frames.push(c)},b.prototype.render=function(){var a,b;if(this.running)throw new Error("Already running");if(null==this.options.width||null==this.options.height)throw new Error("Width and height must be set prior to rendering");this.running=!0,this.nextFrame=0,this.finishedFrames=0,this.imageParts=function(b){for(var c=function(){var a;a=[];for(var b=0;0<=this.frames.length?bthis.frames.length;0<=this.frames.length?++b:--b)a.push(b);return a}.apply(this,arguments),d=0,e=c.length;e>d;++d)a=c[d],b.push(null);return b}.call(this,[]),b=this.spawnWorkers();for(var c=function(){var a;a=[];for(var c=0;b>=0?b>c:c>b;b>=0?++c:--c)a.push(c);return a}.apply(this,arguments),d=0,e=c.length;e>d;++d)a=c[d],this.renderNextFrame();return this.emit("start"),this.emit("progress",0)},b.prototype.abort=function(){for(var a;;){if(a=this.activeWorkers.shift(),!(null!=a))break;console.log("killing active worker"),a.terminate()}return this.running=!1,this.emit("abort")},b.prototype.spawnWorkers=function(){var a;return a=Math.min(this.options.workers,this.frames.length),function(){var b;b=[];for(var c=this.freeWorkers.length;this.freeWorkers.length<=a?a>c:c>a;this.freeWorkers.length<=a?++c:--c)b.push(c);return b}.apply(this,arguments).forEach(function(a){return function(b){var c;return console.log("spawning worker "+b),c=new Worker(a.options.workerScript),c.onmessage=function(a){return function(b){return a.activeWorkers.splice(a.activeWorkers.indexOf(c),1),a.freeWorkers.push(c),a.frameFinished(b.data)}}(a),a.freeWorkers.push(c)}}(this)),a},b.prototype.frameFinished=function(a){return console.log("frame "+a.index+" finished - "+this.activeWorkers.length+" active"),this.finishedFrames++,this.emit("progress",this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,d(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},b.prototype.finishRendering=function(){var a,b,c,d,e,f,g;e=0;for(var h=0,i=this.imageParts.length;i>h;++h)b=this.imageParts[h],e+=(b.data.length-1)*b.pageSize+b.cursor;e+=b.pageSize-b.cursor,console.log("rendering finished - filesize "+Math.round(e/1e3)+"kb"),a=new Uint8Array(e),f=0;for(var j=0,k=this.imageParts.length;k>j;++j){b=this.imageParts[j];for(var l=0,m=b.data.length;m>l;++l)g=b.data[l],c=l,a.set(g,f),f+=c===b.data.length-1?b.cursor:b.pageSize}return d=new Blob([a],{type:"image/gif"}),this.emit("finished",d,a)},b.prototype.renderNextFrame=function(){var a,b,c;if(0===this.freeWorkers.length)throw new Error("No free workers");return this.nextFrame>=this.frames.length?void 0:(a=this.frames[this.nextFrame++],c=this.freeWorkers.shift(),b=this.getTask(a),console.log("starting frame "+(b.index+1)+" of "+this.frames.length),this.activeWorkers.push(c),c.postMessage(b))},b.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},b.prototype.getImageData=function(a){var b;return null!=this._canvas||(this._canvas=document.createElement("canvas"),this._canvas.width=this.options.width,this._canvas.height=this.options.height),b=this._canvas.getContext("2d"),b.setFill=this.options.background,b.fillRect(0,0,this.options.width,this.options.height),b.drawImage(a,0,0),this.getContextData(b)},b.prototype.getTask=function(a){var b,c;if(b=this.frames.indexOf(a),c={index:b,last:b===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,preserveColors:this.options.preserveColors,repeat:this.options.repeat,canTransfer:"chrome"===f.name},null!=a.data)c.data=a.data;else if(null!=a.context)c.data=this.getContextData(a.context);else{if(null==a.image)throw new Error("Invalid frame");c.data=this.getImageData(a.image)}return c},b}(h),a.exports=j}),b.define("/browser.coffee",function(a){var b,c,d,e,f;e=navigator.userAgent.toLowerCase(),d=navigator.platform.toLowerCase(),f=e.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0],c="ie"===f[1]&&document.documentMode,b={name:"version"===f[1]?f[3]:f[1],version:c||parseFloat("opera"===f[1]&&f[4]?f[4]:f[2]),platform:{name:e.match(/ip(?:ad|od|hone)/)?"ios":(e.match(/(?:webos|android)/)||d.match(/mac|win|linux/)||["other"])[0]}},b[b.name]=!0,b[b.name+parseInt(b.version,10)]=!0,b.platform[b.platform.name]=!0,a.exports=b}),b.define("events",function(a,b){c.EventEmitter||(c.EventEmitter=function(){});var d=b.EventEmitter=c.EventEmitter,e="function"==typeof Array.isArray?Array.isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},f=10;d.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},d.prototype.emit=function(a){if("error"===a&&(!this._events||!this._events.error||e(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var b=this._events[a];if(!b)return!1;if("function"!=typeof b){if(e(b)){for(var c=Array.prototype.slice.call(arguments,1),d=b.slice(),f=0,g=d.length;g>f;f++)d[f].apply(this,c);return!0}return!1}switch(arguments.length){case 1:b.call(this);break;case 2:b.call(this,arguments[1]);break;case 3:b.call(this,arguments[1],arguments[2]);break;default:var c=Array.prototype.slice.call(arguments,1);b.apply(this,c)}return!0},d.prototype.addListener=function(a,b){if("function"!=typeof b)throw new Error("addListener only takes instances of Function");if(this._events||(this._events={}),this.emit("newListener",a,b),this._events[a])if(e(this._events[a])){if(!this._events[a].warned){var c;c=void 0!==this._events.maxListeners?this._events.maxListeners:f,c&&c>0&&this._events[a].length>c&&(this._events[a].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];else this._events[a]=b;return this},d.prototype.on=d.prototype.addListener,d.prototype.once=function(a,b){var c=this;return c.on(a,function d(){c.removeListener(a,d),b.apply(this,arguments)}),this},d.prototype.removeListener=function(a,b){if("function"!=typeof b)throw new Error("removeListener only takes instances of Function");if(!this._events||!this._events[a])return this;var c=this._events[a];if(e(c)){var d=c.indexOf(b);if(0>d)return this;c.splice(d,1),0==c.length&&delete this._events[a]}else this._events[a]===b&&delete this._events[a];return this},d.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},d.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),e(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),a.GIF=b("/gif.coffee")}.call(this,this),function(a){"use strict";var b=function(a){this.data=a,this.len=this.data.length,this.pos=0};b.prototype.readByte=function(){if(this.pos>=this.data.length)throw new Error("Attempted to read past end of stream.");return 255&this.data.charCodeAt(this.pos++)},b.prototype.readBytes=function(a){for(var b=[],c=0;a>c;c++)b.push(this.readByte());return b},b.prototype.read=function(a){for(var b="",c=0;a>c;c++)b+=String.fromCharCode(this.readByte());return b},b.prototype.readUnsigned=function(){var a=this.readBytes(2);return(a[1]<<8)+a[0]};var c=a.SuperGIF=a.SuperGIF||{};c.Stream=b}(window),function(a){"use strict";var b=function(a){return a.reduce(function(a,b){return 2*a+b},0)},c=function(a){for(var b=[],c=7;c>=0;c--)b.push(!!(a&1<=this.data.length)throw new Error("Attempted to read past end of stream.");return 255&a.charCodeAt(this.pos++)},this.readBytes=function(a){for(var b=[],c=0;a>c;c++)b.push(this.readByte());return b},this.read=function(a){for(var b="",c=0;a>c;c++)b+=String.fromCharCode(this.readByte());return b},this.readUnsigned=function(){var a=this.readBytes(2);return(a[1]<<8)+a[0]}},e=function(a,b){for(var c,d,e=0,f=function(a){for(var c=0,d=0;a>d;d++)b.charCodeAt(e>>3)&1<<(7&e)&&(c|=1<b;b++)k[b]=[b];k[h]=[],k[i]=null};;)if(d=c,c=f(j),c!==h){if(c===i)break;if(cj&&j++}else l();return g},f=function(a,d){d||(d={});var f=function(b){for(var c=[],d=0;b>d;d++)c.push(a.readBytes(3));return c},g=function(){var b,c;c="";do b=a.readByte(),c+=a.read(b);while(0!==b);return c},h=function(){var e={};if(e.sig=a.read(3),e.ver=a.read(3),"GIF"!==e.sig)throw d.onError(),new Error("Not a GIF file.");e.width=a.readUnsigned(),e.height=a.readUnsigned();var g=c(a.readByte());e.gctFlag=g.shift(),e.colorRes=b(g.splice(0,3)),e.sorted=g.shift(),e.gctSize=b(g.splice(0,3)),e.bgColor=a.readByte(),e.pixelAspectRatio=a.readByte(),e.gctFlag&&(e.gct=f(1<i;i++)for(var j=f[i];d>j;j+=g[i])e(j,h),h++;return c};h.leftPos=a.readUnsigned(),h.topPos=a.readUnsigned(),h.width=a.readUnsigned(),h.height=a.readUnsigned();var j=c(a.readByte());h.lctFlag=j.shift(),h.interlaced=j.shift(),h.sorted=j.shift(),h.reserved=j.splice(0,2),h.lctSize=b(j.splice(0,3)),h.lctFlag&&(h.lct=f(1<0&&(3===o?p.putImageData(r[n].data,0,0):n=b-1,2===o&&p.clearRect(q.leftPos,q.topPos,q.width,q.height));var d=p.getImageData(a.leftPos,a.topPos,a.width,a.height),e=d.data;a.pixels.forEach(function(a,b){a!==k&&(e[4*b+0]=c[a][0],e[4*b+1]=c[a][1],e[4*b+2]=c[a][2],e[4*b+3]=255)}),p.putImageData(d,a.leftPos,a.topPos),q=a},B={hdr:x,gce:y,img:A,eof:function(){z(),j=!1,C&&C()},onError:function(){D&&D()}},C=!1,D=!1,E=document.createElement("canvas");return{load:function(b){if(C=b.success,D=b.error,j=!0,-1!==s.src.indexOf("data:")){var c=s.src.substring(s.src.indexOf(",")+1);g=new d(a.atob(c)),u()}else{var e=new XMLHttpRequest;e.overrideMimeType("text/plain; charset=x-user-defined"),e.onload=function(){g=new d(e.responseText),setTimeout(u,0)},e.onerror=function(){w("xhr")},e.open("GET",s.getAttribute("data-animated-src")||s.src,!0),e.send()}},getFrames:function(){return r}}};a.SuperGif=g}(window),!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZip=a():"undefined"!=typeof global?global.JSZip=a():"undefined"!=typeof self&&(self.JSZip=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,g=(3&b)<<4|c>>4,h=(15&c)<<2|e>>6,i=63&e,isNaN(c)?h=i=64:isNaN(e)&&(i=64),j=j+d.charAt(f)+d.charAt(g)+d.charAt(h)+d.charAt(i);return j},c.decode=function(a){var b,c,e,f,g,h,i,j="",k=0;for(a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");k>4,c=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(b),64!=h&&(j+=String.fromCharCode(c)),64!=i&&(j+=String.fromCharCode(e));return j}},{}],2:[function(a,b){"use strict";function c(){this.compressedSize=0,this.uncompressedSize=0,this.crc32=0,this.compressionMethod=null,this.compressedContent=null}c.prototype={getContent:function(){return null},getCompressedContent:function(){return null}},b.exports=c},{}],3:[function(a,b,c){"use strict";c.STORE={magic:"\x00\x00",compress:function(a){return a},uncompress:function(a){return a},compressInputType:null,uncompressInputType:null},c.DEFLATE=a("./flate")},{"./flate":6}],4:[function(a,b){"use strict";function c(){this.data=null,this.length=0,this.index=0}var d=a("./utils");c.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.lengtha)throw new Error("End of data reached (data length = "+this.length+", asked index = "+a+"). Corrupted zip ?")},setIndex:function(a){this.checkIndex(a),this.index=a},skip:function(a){this.setIndex(this.index+a)},byteAt:function(){},readInt:function(a){var b,c=0;for(this.checkOffset(a),b=this.index+a-1;b>=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return d.transformTo("string",this.readData(a))},readData:function(){},lastIndexOfSignature:function(){},readDate:function(){var a=this.readInt(4);return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1)}},b.exports=c},{"./utils":14}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.date=null,c.compression=null},{}],6:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,e=a("zlibjs/bin/rawdeflate.min").Zlib,f=a("zlibjs/bin/rawinflate.min").Zlib;c.uncompressInputType=d?"uint8array":"array",c.compressInputType=d?"uint8array":"array",c.magic="\b\x00",c.compress=function(a){var b=new e.RawDeflate(a);return b.compress()},c.uncompress=function(a){var b=new f.RawInflate(a);return b.decompress()}},{"zlibjs/bin/rawdeflate.min":19,"zlibjs/bin/rawinflate.min":20}],7:[function(a,b){"use strict";function c(a,b){return this instanceof c?(this.files={},this.root="",a&&this.load(a,b),void(this.clone=function(){var a=new c;for(var b in this)"function"!=typeof this[b]&&(a[b]=this[b]);return a})):new c(a,b)}c.prototype=a("./object"),c.prototype.load=a("./load"),c.support=a("./support"),c.defaults=a("./defaults"),c.utils=a("./utils"),c.base64=a("./base64"),c.compressions=a("./compressions"),b.exports=c},{"./base64":1,"./compressions":3,"./defaults":5,"./load":8,"./object":9,"./support":12,"./utils":14}],8:[function(a,b){"use strict";var c=a("./base64"),d=a("./zipEntries");b.exports=function(a,b){var e,f,g,h;for(b=b||{},b.base64&&(a=c.decode(a)),f=new d(a,b),e=f.files,g=0;gc;c++)d+=String.fromCharCode(255&a),a>>>=8;return d},r=function(){var a,b,c={};for(a=0;a0?a.substring(0,b):""},v=function(a){return"/"!=a.slice(-1)&&(a+="/"),this.files[a]||t.call(this,a,null,{dir:!0}),this.files[a]},w=function(a,b){var c,d=new k;return a._data instanceof k?(d.uncompressedSize=a._data.uncompressedSize,d.crc32=a._data.crc32,0===d.uncompressedSize||a.options.dir?(b=j.STORE,d.compressedContent="",d.crc32=0):a._data.compressionMethod===b.magic?d.compressedContent=a._data.getCompressedContent():(c=a._data.getContent(),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c)))):(c=n(a),(!c||0===c.length||a.options.dir)&&(b=j.STORE,c=""),d.uncompressedSize=c.length,d.crc32=this.crc32(c),d.compressedContent=b.compress(f.transformTo(b.compressInputType,c))),d.compressedSize=d.compressedContent.length,d.compressionMethod=b.magic,d},x=function(a,b,c,d){var e,f,h=(c.compressedContent,this.utf8encode(b.name)),i=h!==b.name,j=b.options,k="",l="";e=j.date.getHours(),e<<=6,e|=j.date.getMinutes(),e<<=5,e|=j.date.getSeconds()/2,f=j.date.getFullYear()-1980,f<<=4,f|=j.date.getMonth()+1,f<<=5,f|=j.date.getDate(),i&&(l=q(1,1)+q(this.crc32(h),4)+h,k+="up"+q(l.length,2)+l);var m="";m+="\n\x00",m+=i?"\x00\b":"\x00\x00",m+=c.compressionMethod,m+=q(e,2),m+=q(f,2),m+=q(c.crc32,4),m+=q(c.compressedSize,4),m+=q(c.uncompressedSize,4),m+=q(h.length,2),m+=q(k.length,2);var n=g.LOCAL_FILE_HEADER+m+h+k,o=g.CENTRAL_FILE_HEADER+"\x00"+m+"\x00\x00\x00\x00\x00\x00"+(b.options.dir===!0?"\x00\x00\x00":"\x00\x00\x00\x00")+q(d,4)+h+k;return{fileRecord:n,dirRecord:o,compressedObject:c}},y=function(){this.data=[]};y.prototype={append:function(a){a=f.transformTo("string",a),this.data.push(a)},finalize:function(){return this.data.join("")}};var z=function(a){this.data=new Uint8Array(a),this.index=0};z.prototype={append:function(a){0!==a.length&&(a=f.transformTo("uint8array",a),this.data.set(a,this.index),this.index+=a.length)},finalize:function(){return this.data}};var A={load:function(){throw new Error("Load method is not defined. Is the file jszip-load.js included ?")},filter:function(a){var b,c,d,e,f=[];for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],e=new p(d.name,d._data,r(d.options)),c=b.slice(this.root.length,b.length),b.slice(0,this.root.length)===this.root&&a(c,e)&&f.push(e));return f},file:function(a,b,c){if(1===arguments.length){if(f.isRegExp(a)){var d=a;return this.filter(function(a,b){return!b.options.dir&&d.test(a)})}return this.filter(function(b,c){return!c.options.dir&&b===a})[0]||null}return a=this.root+a,t.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(f.isRegExp(a))return this.filter(function(b,c){return c.options.dir&&a.test(b)});var b=this.root+a,c=v.call(this,b),d=this.clone();return d.root=c.name,d},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!=a.slice(-1)&&(a+="/"),b=this.files[a]),b)if(b.options.dir)for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;di;i++)h=c?a[i]:a.charCodeAt(i),g=255&(b^h),e=d[g],b=b>>>8^e;return-1^b},utf8encode:function(a){if(c){var b=c.encode(a);return f.transformTo("string",b)}if(e.nodebuffer)return f.transformTo("string",l(a,"utf-8"));for(var d=[],g=0,h=0;hi?d[g++]=String.fromCharCode(i):i>127&&2048>i?(d[g++]=String.fromCharCode(i>>6|192),d[g++]=String.fromCharCode(63&i|128)):(d[g++]=String.fromCharCode(i>>12|224),d[g++]=String.fromCharCode(i>>6&63|128),d[g++]=String.fromCharCode(63&i|128))}return d.join("")},utf8decode:function(a){var b=[],c=0,g=f.getTypeOf(a),h="string"!==g,i=0,j=0,k=0,l=0;if(d)return d.decode(f.transformTo("uint8array",a));if(e.nodebuffer)return f.transformTo("nodebuffer",a).toString("utf-8");for(;ij?(b[c++]=String.fromCharCode(j),i++):j>191&&224>j?(k=h?a[i+1]:a.charCodeAt(i+1),b[c++]=String.fromCharCode((31&j)<<6|63&k),i+=2):(k=h?a[i+1]:a.charCodeAt(i+1),l=h?a[i+2]:a.charCodeAt(i+2),b[c++]=String.fromCharCode((15&j)<<12|(63&k)<<6|63&l),i+=3);return b.join("")}};b.exports=A -},{"./base64":1,"./compressedObject":2,"./compressions":3,"./defaults":5,"./nodeBuffer":17,"./signature":10,"./support":12,"./utils":14}],10:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],11:[function(a,b){"use strict";function c(a,b){this.data=a,b||(this.data=e.string2binary(this.data)),this.length=this.data.length,this.index=0}var d=a("./dataReader"),e=a("./utils");c.prototype=new d,c.prototype.byteAt=function(a){return this.data.charCodeAt(a)},c.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4,"./utils":14}],12:[function(a,b,c){var d=a("__browserify_process");if(c.base64=!0,c.array=!0,c.string=!0,c.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,c.nodebuffer=!d.browser,c.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)c.blob=!1;else{var e=new ArrayBuffer(0);try{c.blob=0===new Blob([e],{type:"application/zip"}).size}catch(f){try{var g=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,h=new g;h.append(e),c.blob=0===h.getBlob("application/zip").size}catch(f){c.blob=!1}}}},{__browserify_process:18}],13:[function(a,b){"use strict";function c(a){a&&(this.data=a,this.length=this.data.length,this.index=0)}var d=a("./dataReader");c.prototype=new d,c.prototype.byteAt=function(a){return this.data[a]},c.prototype.lastIndexOfSignature=function(a){for(var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.length-4;f>=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f;return-1},c.prototype.readData=function(a){this.checkOffset(a);var b=this.data.subarray(this.index,this.index+a);return this.index+=a,b},b.exports=c},{"./dataReader":4}],14:[function(a,b,c){"use strict";function d(a){return a}function e(a,b){for(var c=0;cg&&b>1;)try{d.push("array"===f||"nodebuffer"===f?String.fromCharCode.apply(null,a.slice(g,Math.min(g+b,e))):String.fromCharCode.apply(null,a.subarray(g,Math.min(g+b,e)))),g+=b}catch(i){b=Math.floor(b/2)}return d.join("")}function g(a,b){for(var c=0;cb?"0":"")+b.toString(16).toUpperCase();return d},c.findCompression=function(a){for(var b in i)if(i.hasOwnProperty(b)&&i[b].magic===a)return i[b];return null},c.isRegExp=function(a){return"[object RegExp]"===Object.prototype.toString.call(a)}},{"./compressions":3,"./nodeBuffer":17,"./support":12}],15:[function(a,b){"use strict";function c(a,b){this.files=[],this.loadOptions=b,a&&this.load(a)}var d=a("./stringReader"),e=a("./nodeBufferReader"),f=a("./uint8ArrayReader"),g=a("./utils"),h=a("./signature"),i=a("./zipEntry"),j=a("./support");c.prototype={checkSignature:function(a){var b=this.reader.readString(4);if(b!==a)throw new Error("Corrupted zip or bug : unexpected signature ("+g.pretty(b)+", expected "+g.pretty(a)+")")},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2),this.zipComment=this.reader.readString(this.zipCommentLength)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.versionMadeBy=this.reader.readString(2),this.versionNeeded=this.reader.readInt(2),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var a,b,c,d=this.zip64EndOfCentralSize-44,e=0;d>e;)a=this.reader.readInt(2),b=this.reader.readInt(4),c=this.reader.readString(b),this.zip64ExtensibleData[a]={id:a,length:b,value:c}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),this.disksCount>1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)){var d=c.shift();d()}},!0),function(a){c.push(a),window.postMessage("process-tick","*")}}return function(a){setTimeout(a,0)}}(),c.title="browser",c.browser=!0,c.env={},c.argv=[],c.binding=function(){throw new Error("process.binding is not supported")},c.cwd=function(){return"/"},c.chdir=function(){throw new Error("process.chdir is not supported")}},{}],19:[function(){(function(){"use strict";function a(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||b===l?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a,b){if(this.index="number"==typeof b?b:0,this.d=0,this.buffer=a instanceof(o?Uint8Array:Array)?a:new(o?Uint8Array:Array)(32768),2*this.buffer.length<=this.index)throw Error("invalid index");this.buffer.length<=this.index&&c(this)}function c(a){var b,c=a.buffer,d=c.length,e=new(o?Uint8Array:Array)(d<<1);if(o)e.set(c);else for(b=0;d>b;++b)e[b]=c[b];return a.buffer=e}function d(a){this.buffer=new(o?Uint16Array:Array)(2*a),this.length=0}function e(a,b){this.e=w,this.f=0,this.input=o&&a instanceof Array?new Uint8Array(a):a,this.c=0,b&&(b.lazy&&(this.f=b.lazy),"number"==typeof b.compressionType&&(this.e=b.compressionType),b.outputBuffer&&(this.b=o&&b.outputBuffer instanceof Array?new Uint8Array(b.outputBuffer):b.outputBuffer),"number"==typeof b.outputIndex&&(this.c=b.outputIndex)),this.b||(this.b=new(o?Uint8Array:Array)(32768))}function f(a,b){this.length=a,this.g=b}function g(a,b){function c(a,b){var c,d=a.g,e=[],f=0;c=z[a.length],e[f++]=65535&c,e[f++]=c>>16&255,e[f++]=c>>24;var g;switch(m){case 1===d:g=[0,d-1,0];break;case 2===d:g=[1,d-2,0];break;case 3===d:g=[2,d-3,0];break;case 4===d:g=[3,d-4,0];break;case 6>=d:g=[4,d-5,1];break;case 8>=d:g=[5,d-7,1];break;case 12>=d:g=[6,d-9,2];break;case 16>=d:g=[7,d-13,2];break;case 24>=d:g=[8,d-17,3];break;case 32>=d:g=[9,d-25,3];break;case 48>=d:g=[10,d-33,4];break;case 64>=d:g=[11,d-49,4];break;case 96>=d:g=[12,d-65,5];break;case 128>=d:g=[13,d-97,5];break;case 192>=d:g=[14,d-129,6];break;case 256>=d:g=[15,d-193,6];break;case 384>=d:g=[16,d-257,7];break;case 512>=d:g=[17,d-385,7];break;case 768>=d:g=[18,d-513,8];break;case 1024>=d:g=[19,d-769,8];break;case 1536>=d:g=[20,d-1025,9];break;case 2048>=d:g=[21,d-1537,9];break;case 3072>=d:g=[22,d-2049,10];break;case 4096>=d:g=[23,d-3073,10];break;case 6144>=d:g=[24,d-4097,11];break;case 8192>=d:g=[25,d-6145,11];break;case 12288>=d:g=[26,d-8193,12];break;case 16384>=d:g=[27,d-12289,12];break;case 24576>=d:g=[28,d-16385,13];break;case 32768>=d:g=[29,d-24577,13];break;default:throw"invalid distance"}c=g,e[f++]=c[0],e[f++]=c[1],e[f++]=c[2];var h,i;for(h=0,i=e.length;i>h;++h)r[s++]=e[h];u[e[0]]++,v[e[3]]++,t=a.length+b-1,n=null}var d,e,f,g,i,j,k,n,p,q={},r=o?new Uint16Array(2*b.length):[],s=0,t=0,u=new(o?Uint32Array:Array)(286),v=new(o?Uint32Array:Array)(30),w=a.f;if(!o){for(f=0;285>=f;)u[f++]=0;for(f=0;29>=f;)v[f++]=0}for(u[256]=1,d=0,e=b.length;e>d;++d){for(f=i=0,g=3;g>f&&d+f!==e;++f)i=i<<8|b[d+f];if(q[i]===l&&(q[i]=[]),j=q[i],!(0=e){for(n&&c(n,-1),f=0,g=e-d;g>f;++f)p=b[d+f],r[s++]=p,++u[p];break}0h;h++){if(d=c[j-h-1],g=3,k>3){for(i=k;i>3;i--)if(a[d+i-1]!==a[b+i-1])continue a;g=k}for(;258>g&&l>b+g&&a[d+g]===a[b+g];)++g;if(g>k&&(e=d,k=g),258===g)break}return new f(k,b-e)}function i(a,b){var c,e,f,g,h,i=a.length,k=new d(572),l=new(o?Uint8Array:Array)(i);if(!o)for(g=0;i>g;g++)l[g]=0;for(g=0;i>g;++g)0g;++g)c[g]=k.pop(),e[g]=c[g].value;for(f=j(e,e.length,b),g=0,h=c.length;h>g;++g)l[c[g].index]=f[g];return l}function j(a,b,c){function d(a){var c=n[a][p[a]];c===b?(d(a+1),d(a+1)):--l[c],++p[a]}var e,f,g,h,i,j=new(o?Uint16Array:Array)(c),k=new(o?Uint8Array:Array)(c),l=new(o?Uint8Array:Array)(b),m=Array(c),n=Array(c),p=Array(c),q=(1<f;++f)r>q?k[f]=0:(k[f]=1,q-=r),q<<=1,j[c-2-f]=(j[c-1-f]/2|0)+b;for(j[0]=k[0],m[0]=Array(j[0]),n[0]=Array(j[0]),f=1;c>f;++f)j[f]>2*j[f-1]+k[f]&&(j[f]=2*j[f-1]+k[f]),m[f]=Array(j[f]),n[f]=Array(j[f]);for(e=0;b>e;++e)l[e]=c;for(g=0;ge;++e)p[e]=0;for(1===k[c-1]&&(--l[0],++p[c-1]),f=c-2;f>=0;--f){for(h=e=0,i=p[f+1],g=0;ga[e]?(m[f][g]=h,n[f][g]=b,i+=2):(m[f][g]=a[e],n[f][g]=e,++e);p[f]=0,1===k[f]&&d(f)}return l}function k(a){var b,c,d,e,f=new(o?Uint16Array:Array)(a.length),g=[],h=[],i=0;for(b=0,c=a.length;c>b;b++)g[a[b]]=(0|g[a[b]])+1;for(b=1,c=16;c>=b;b++)h[b]=i,i+=0|g[b],i<<=1;for(b=0,c=a.length;c>b;b++)for(i=h[a[b]],h[a[b]]+=1,d=f[b]=0,e=a[b];e>d;d++)f[b]=f[b]<<1|1&i,i>>>=1;return f}var l=void 0,m=!0,n=this,o="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView;b.prototype.a=function(a,b,d){var e,f=this.buffer,g=this.index,h=this.d,i=f[g];if(d&&b>1&&(a=b>8?(u[255&a]<<24|u[a>>>8&255]<<16|u[a>>>16&255]<<8|u[a>>>24&255])>>32-b:u[a]>>8-b),8>b+h)i=i<e;++e)i=i<<1|a>>b-e-1&1,8===++h&&(h=0,f[g++]=u[i],i=0,g===f.length&&(f=c(this)));f[g]=i,this.buffer=f,this.d=h,this.index=g},b.prototype.finish=function(){var a,b=this.buffer,c=this.index;return 0p;++p){for(var r=p,s=r,t=7,r=r>>>1;r;r>>>=1)s<<=1,s|=1&r,--t;q[p]=(s<>>0}var u=q;d.prototype.getParent=function(a){return 2*((a-2)/4|0)},d.prototype.push=function(a,b){var c,d,e,f=this.buffer;for(c=this.length,f[this.length++]=b,f[this.length++]=a;c>0&&(d=this.getParent(c),f[c]>f[d]);)e=f[c],f[c]=f[d],f[d]=e,e=f[c+1],f[c+1]=f[d+1],f[d+1]=e,c=d;return this.length},d.prototype.pop=function(){var a,b,c,d,e,f=this.buffer;for(b=f[0],a=f[1],this.length-=2,f[0]=f[this.length],f[1]=f[this.length+1],e=0;d=2*e+2,!(d>=this.length)&&(d+2f[d]&&(d+=2),f[d]>f[e]);)c=f[e],f[e]=f[d],f[d]=c,c=f[e+1],f[e+1]=f[d+1],f[d+1]=c,e=d;return{index:a,value:b,length:this.length}};var v,w=2,x=[];for(v=0;288>v;v++)switch(m){case 143>=v:x.push([v+48,8]);break;case 255>=v:x.push([v-144+400,9]);break;case 279>=v:x.push([v-256+0,7]);break;case 287>=v:x.push([v-280+192,8]);break;default:throw"invalid literal: "+v}e.prototype.h=function(){var a,c,d,e,f=this.input;switch(this.e){case 0:for(d=0,e=f.length;e>d;){c=o?f.subarray(d,d+65535):f.slice(d,d+65535),d+=c.length;var h=c,j=d===e,n=l,p=l,q=l,r=l,s=l,t=this.b,u=this.c;if(o){for(t=new Uint8Array(this.b.buffer);t.length<=u+h.length+5;)t=new Uint8Array(t.length<<1);t.set(this.b)}if(n=j?1:0,t[u++]=0|n,p=h.length,q=~p+65536&65535,t[u++]=255&p,t[u++]=p>>>8&255,t[u++]=255&q,t[u++]=q>>>8&255,o)t.set(h,u),u+=h.length,t=t.subarray(0,u);else{for(r=0,s=h.length;s>r;++r)t[u++]=h[r];t.length=u}this.c=u,this.b=t}break;case 1:var v=new b(o?new Uint8Array(this.b.buffer):this.b,this.c);v.a(1,1,m),v.a(1,2,m);var y,z,A,B=g(this,f);for(y=0,z=B.length;z>y;y++)if(A=B[y],b.prototype.a.apply(v,x[A]),A>256)v.a(B[++y],B[++y],m),v.a(B[++y],5),v.a(B[++y],B[++y],m);else if(256===A)break;this.b=v.finish(),this.c=this.b.length;break;case w:var C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R=new b(o?new Uint8Array(this.b.buffer):this.b,this.c),S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],T=Array(19);for(C=w,R.a(1,1,m),R.a(C,2,m),D=g(this,f),H=i(this.j,15),I=k(H),J=i(this.i,7),K=k(J),E=286;E>257&&0===H[E-1];E--);for(F=30;F>1&&0===J[F-1];F--);var U,V,W,X,Y,Z,$=E,_=F,ab=new(o?Uint32Array:Array)($+_),bb=new(o?Uint32Array:Array)(316),cb=new(o?Uint8Array:Array)(19);for(U=V=0;$>U;U++)ab[V++]=H[U];for(U=0;_>U;U++)ab[V++]=J[U];if(!o)for(U=0,X=cb.length;X>U;++U)cb[U]=0;for(U=Y=0,X=ab.length;X>U;U+=V){for(V=1;X>U+V&&ab[U+V]===ab[U];++V);if(W=V,0===ab[U])if(3>W)for(;00;)Z=138>W?W:138,Z>W-3&&W>Z&&(Z=W-3),10>=Z?(bb[Y++]=17,bb[Y++]=Z-3,cb[17]++):(bb[Y++]=18,bb[Y++]=Z-11,cb[18]++),W-=Z;else if(bb[Y++]=ab[U],cb[ab[U]]++,W--,3>W)for(;00;)Z=6>W?W:6,Z>W-3&&W>Z&&(Z=W-3),bb[Y++]=16,bb[Y++]=Z-3,cb[16]++,W-=Z}for(a=o?bb.subarray(0,Y):bb.slice(0,Y),L=i(cb,7),P=0;19>P;P++)T[P]=L[S[P]];for(G=19;G>4&&0===T[G-1];G--);for(M=k(L),R.a(E-257,5,m),R.a(F-1,5,m),R.a(G-4,4,m),P=0;G>P;P++)R.a(T[P],3,m);for(P=0,Q=a.length;Q>P;P++)if(N=a[P],R.a(M[N],L[N],m),N>=16){switch(P++,N){case 16:O=2;break;case 17:O=3;break;case 18:O=7;break;default:throw"invalid code: "+N}R.a(a[P],O,m)}var db,eb,fb,gb,hb,ib,jb,kb,lb=[I,H],mb=[K,J];for(hb=lb[0],ib=lb[1],jb=mb[0],kb=mb[1],db=0,eb=D.length;eb>db;++db)if(fb=D[db],R.a(hb[fb],ib[fb],m),fb>256)R.a(D[++db],D[++db],m),gb=D[++db],R.a(jb[gb],kb[gb],m),R.a(D[++db],D[++db],m);else if(256===fb)break;this.b=R.finish(),this.c=this.b.length;break;default:throw"invalid compression type"}return this.b};var y=function(){function a(a){switch(m){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a}}var b,c,d=[];for(b=3;258>=b;b++)c=a(b),d[b]=c[2]<<24|c[1]<<16|c[0];return d}(),z=o?new Uint32Array(y):y;a("Zlib.RawDeflate",e),a("Zlib.RawDeflate.prototype.compress",e.prototype.h);var A,B,C,D,E={NONE:0,FIXED:1,DYNAMIC:w};if(Object.keys)A=Object.keys(E);else for(B in A=[],C=0,E)A[C++]=B;for(C=0,D=A.length;D>C;++C)B=A[C],a("Zlib.RawDeflate.CompressionType."+B,E[B])}).call(this)},{}],20:[function(){(function(){"use strict";function a(a,b){var c=a.split("."),d=g;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d=d[e]?d[e]:d[e]={}:d[e]=b}function b(a){var b,c,d,e,f,g,i,j,k,l,m=a.length,n=0,o=Number.POSITIVE_INFINITY;for(j=0;m>j;++j)a[j]>n&&(n=a[j]),a[j]=d;){for(j=0;m>j;++j)if(a[j]===d){for(g=0,i=e,k=0;d>k;++k)g=g<<1|1&i,i>>=1;for(l=d<<16|j,k=g;b>k;k+=f)c[k]=l;++e}++d,e<<=1,f<<=1}return[c,n,o]}function c(a,b){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=h?new Uint8Array(a):a,this.l=!1,this.i=j,this.q=!1,(b||!(b={}))&&(b.index&&(this.d=b.index),b.bufferSize&&(this.h=b.bufferSize),b.bufferType&&(this.i=b.bufferType),b.resize&&(this.q=b.resize)),this.i){case i:this.a=32768,this.b=new(h?Uint8Array:Array)(32768+this.h+258);break;case j:this.a=0,this.b=new(h?Uint8Array:Array)(this.h),this.e=this.v,this.m=this.s,this.j=this.t;break;default:throw Error("invalid inflate mode")}}function d(a,b){for(var c,d=a.f,e=a.c,f=a.input,g=a.d,h=f.length;b>e;){if(g>=h)throw Error("input buffer is broken");d|=f[g++]<>>b,a.c=e-b,a.d=g,c}function e(a,b){for(var c,d,e=a.f,f=a.c,g=a.input,h=a.d,i=g.length,j=b[0],k=b[1];k>f&&!(h>=i);)e|=g[h++]<>>16,a.f=e>>d,a.c=f-d,a.d=h,65535&c}function f(a){function c(a,b,c){var f,g,h,i=this.p;for(h=0;a>h;)switch(f=e(this,b)){case 16:for(g=3+d(this,2);g--;)c[h++]=i;break;case 17:for(g=3+d(this,3);g--;)c[h++]=0;i=0;break;case 18:for(g=11+d(this,7);g--;)c[h++]=0;i=0;break;default:i=c[h++]=f}return this.p=i,c}var f,g,i,j,k=d(a,5)+257,l=d(a,5)+1,m=d(a,4)+4,o=new(h?Uint8Array:Array)(n.length);for(j=0;m>j;++j)o[n[j]]=d(a,3);if(!h)for(j=m,m=o.length;m>j;++j)o[n[j]]=0;f=b(o),g=new(h?Uint8Array:Array)(k),i=new(h?Uint8Array:Array)(l),a.p=0,a.j(b(c.call(a,k,f,g)),b(c.call(a,l,f,i)))}var g=this,h="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array&&"undefined"!=typeof DataView,i=0,j=1;c.prototype.u=function(){for(;!this.l;){var a=d(this,3);switch(1&a&&(this.l=!0),a>>>=1){case 0:var b=this.input,c=this.d,e=this.b,g=this.a,k=b.length,l=void 0,m=void 0,n=e.length,o=void 0;if(this.c=this.f=0,c+1>=k)throw Error("invalid uncompressed block header: LEN");if(l=b[c++]|b[c++]<<8,c+1>=k)throw Error("invalid uncompressed block header: NLEN");if(m=b[c++]|b[c++]<<8,l===~m)throw Error("invalid uncompressed block header: length verify");if(c+l>b.length)throw Error("input buffer is broken");switch(this.i){case i:for(;g+l>e.length;){if(o=n-g,l-=o,h)e.set(b.subarray(c,c+o),g),g+=o,c+=o;else for(;o--;)e[g++]=b[c++];this.a=g,e=this.e(),g=this.a}break;case j:for(;g+l>e.length;)e=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(h)e.set(b.subarray(c,c+l),g),g+=l,c+=l;else for(;l--;)e[g++]=b[c++];this.d=c,this.a=g,this.b=e;break;case 1:this.j(z,B);break;case 2:f(this);break;default:throw Error("unknown BTYPE: "+a)}}return this.m()};var k,l,m=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],n=h?new Uint16Array(m):m,o=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],p=h?new Uint16Array(o):o,q=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],r=h?new Uint8Array(q):q,s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],t=h?new Uint16Array(s):s,u=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],v=h?new Uint8Array(u):u,w=new(h?Uint8Array:Array)(288);for(k=0,l=w.length;l>k;++k)w[k]=143>=k?8:255>=k?9:279>=k?7:8;var x,y,z=b(w),A=new(h?Uint8Array:Array)(30);for(x=0,y=A.length;y>x;++x)A[x]=5;var B=b(A);c.prototype.j=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length-258;256!==(g=e(this,a));)if(256>g)f>=k&&(this.a=f,c=this.e(),f=this.a),c[f++]=g;else for(h=g-257,j=p[h],0=k&&(this.a=f,c=this.e(),f=this.a);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.t=function(a,b){var c=this.b,f=this.a;this.n=a;for(var g,h,i,j,k=c.length;256!==(g=e(this,a));)if(256>g)f>=k&&(c=this.e(),k=c.length),c[f++]=g;else for(h=g-257,j=p[h],0k&&(c=this.e(),k=c.length);j--;)c[f]=c[f++-i];for(;8<=this.c;)this.c-=8,this.d--;this.a=f},c.prototype.e=function(){var a,b,c=new(h?Uint8Array:Array)(this.a-32768),d=this.a-32768,e=this.b;if(h)c.set(e.subarray(32768,c.length));else for(a=0,b=c.length;b>a;++a)c[a]=e[a+32768];if(this.g.push(c),this.k+=c.length,h)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];return this.a=32768,e},c.prototype.v=function(a){var b,c,d,e,f=this.input.length/this.d+1|0,g=this.input,i=this.b;return a&&("number"==typeof a.o&&(f=a.o),"number"==typeof a.r&&(f+=a.r)),2>f?(c=(g.length-this.d)/this.n[2],e=258*(c/2)|0,d=eb;++b)for(a=i[b],d=0,e=a.length;e>d;++d)j[f++]=a[d];for(b=32768,c=this.a;c>b;++b)j[f++]=g[b];return this.g=[],this.buffer=j},c.prototype.s=function(){var a,b=this.a;return h?this.q?(a=new Uint8Array(b),a.set(this.b.subarray(0,b))):a=this.b.subarray(0,b):(this.b.length>b&&(this.b.length=b),a=this.b),this.buffer=a},a("Zlib.RawInflate",c),a("Zlib.RawInflate.prototype.decompress",c.prototype.u);var C,D,E,F,G={ADAPTIVE:j,BLOCK:i};if(Object.keys)C=Object.keys(G);else for(D in C=[],E=0,G)C[E++]=D;for(E=0,F=C.length;F>E;++E)D=C[E],a("Zlib.RawInflate.BufferType."+D,G[D])}).call(this)},{}]},{},[7])(7)}),function(a,b,c){function d(a,b,c){for(var d=[],e=0;e')}return"
        "+d.join("")+"
        "}function e(){for(var a=0;a1&&(delete a.localStorage[W],b.each(e,function(a,b){t(b)}))}catch(f){}try{nb=a.localStorage[W].split(";")}catch(f){}}Kb.bind("click.spectrum touchstart.spectrum",function(a){tb||B(),a.stopPropagation(),b(a.target).is("input")||a.preventDefault()}),(sb.is(":disabled")||T.disabled===!0)&&S(),ub.click(j),Cb.change(A),Cb.bind("paste",function(){setTimeout(A,1)}),Cb.keydown(function(a){13==a.keyCode&&A()}),Fb.text(T.cancelText),Fb.bind("click.spectrum",function(a){a.stopPropagation(),a.preventDefault(),F("cancel")}),Gb.text(T.chooseText),Gb.bind("click.spectrum",function(a){a.stopPropagation(),a.preventDefault(),J()&&(N(!0),F())}),l(Ab,function(a,b,c){kb=a/eb,c.shiftKey&&(kb=Math.round(10*kb)/10),K() -}),l(xb,function(a,b){hb=parseFloat(b/cb),K()},y,z),l(vb,function(a,b,c){if(c.shiftKey){if(!qb){var d=ib*_,e=ab-jb*ab,f=Math.abs(a-d)>Math.abs(b-e);qb=f?"x":"y"}}else qb=null;var g=!qb||"x"===qb,h=!qb||"y"===qb;g&&(ib=parseFloat(a/_)),h&&(jb=parseFloat((ab-b)/ab)),K()},y,z),Mb?(H(Mb),L(),Pb=Ob||u(Mb).format,t(Mb)):L(),U&&C();var g=p?"mousedown.spectrum":"click.spectrum touchstart.spectrum";Db.delegate(".sp-thumb-el",g,c),Eb.delegate(".sp-thumb-el:nth-child(1)",g,{ignore:!0},c)}function t(c){if(V){var d=u(c).toRgbString();if(-1===b.inArray(d,nb))for(nb.push(d);nb.length>ob;)nb.shift();if(W&&a.localStorage)try{a.localStorage[W]=nb.join(";")}catch(e){}}}function v(){var a,b=[],c=nb,d={};if(T.showPalette){for(var e=0;e=ab||0>=_||0>=cb)&&O(),ub.addClass(pb),qb=null}function z(){ub.removeClass(pb)}function A(){var a=u(Cb.val());a.ok?H(a):Cb.addClass("sp-validation-error")}function B(){$?F():C()}function C(){var c=b.Event("beforeShow.spectrum");return $?void O():(Nb=I(),sb.trigger(c,[Nb]),void(Y.beforeShow(Nb)===!1||c.isDefaultPrevented()||(H(Nb),e(),$=!0,b(rb).bind("mousedown.spectrum",D),b(rb).bind("mouseup.spectrum",E),b(a).bind("resize.spectrum",Z),Jb.addClass("sp-active"),ub.removeClass("sp-hidden"),T.showPalette&&w(),O(),L(),x(),Y.show(Nb),sb.trigger("show.spectrum",[Nb]))))}function D(a){var c=b(a.target),d=c.parents(),e=!d.is(ub)&&!c.is(ub);e&&F(a)}function E(a){var b=!u.equals(I(),Nb);b&&(Qb&&"cancel"!==a?N(!0):G())}function F(c){c&&"click"==c.type&&2==c.button||$&&!U&&($=!1,b(rb).unbind("mousedown.spectrum",D),b(rb).unbind("mouseup.spectrum",E),b(a).unbind("resize.spectrum",Z),Jb.removeClass("sp-active"),ub.addClass("sp-hidden"),E(c),t(I()),Y.hide(I()),sb.trigger("hide.spectrum",[I()]))}function G(){H(Nb,!0)}function H(a,b){if(!u.equals(a,I())){var c=u(a),d=c.toHsv();hb=d.h%360/360,ib=d.s,jb=d.v,kb=d.a,L(),c.ok&&!b&&(Pb=Ob||c.format)}}function I(a){return a=a||{},u.fromRatio({h:hb,s:ib,v:jb,a:Math.round(100*kb)/100},{format:a.format||Pb})}function J(){return!Cb.hasClass("sp-validation-error")}function K(){L(),Y.move(I()),sb.trigger("move.spectrum",[I()])}function L(){Cb.removeClass("sp-validation-error"),M();var a=u.fromRatio({h:hb,s:1,v:1});vb.css("background-color",a.toHexString());var b=Pb;1>kb&&("hex"===b||"hex3"===b||"hex6"===b||"name"===b)&&(b="rgb");var c=I({format:b}),d=c.toHexString(),e=c.toRgbString();if(q||1===c.alpha?Lb.css("background-color",e):(Lb.css("background-color","transparent"),Lb.css("filter",c.toFilter())),T.showAlpha){var f=c.toRgb();f.a=0;var g=u(f).toRgbString(),h="linear-gradient(left, "+g+", "+d+")";p?zb.css("filter",u(g).toFilter({gradientType:1},d)):(zb.css("background","-webkit-"+h),zb.css("background","-moz-"+h),zb.css("background","-ms-"+h),zb.css("background",h))}T.showInput&&Cb.val(c.toString(Constants.PREFERRED_COLOR_FORMAT||b)),T.showPalette&&w(),x()}function M(){var a=ib,b=jb,c=a*_,d=ab-b*ab;c=Math.max(-bb/2,Math.min(_-bb/2,c-bb/2)),d=Math.max(-bb/2,Math.min(ab-bb/2,d-bb/2)),wb.css({top:d,left:c});var e=kb*eb;Bb.css({left:e-fb/2});var f=hb*cb;yb.css({top:f-gb/2})}function N(a){var b=I();Hb&&sb.val(b.toString(Pb));var c=!u.equals(b,Nb);Nb=b,a&&c&&(Y.change(b),sb.trigger("change",[b]))}function O(){_=vb.width(),ab=vb.height(),bb=wb.height()+4,db=xb.width(),cb=xb.height(),gb=yb.height()+4,eb=Ab.width(),fb=Bb.width(),U||(ub.css("position","absolute"),ub.offset(h(ub,Kb))),M()}function P(){sb.show(),Kb.unbind("click.spectrum touchstart.spectrum"),ub.remove(),Jb.remove(),o[Rb.id]=null}function Q(a,d){return a===c?b.extend({},T):d===c?T[a]:(T[a]=d,void k())}function R(){tb=!1,sb.attr("disabled",!1),Kb.removeClass("sp-disabled")}function S(){F(),tb=!0,sb.attr("disabled",!0),Kb.addClass("sp-disabled")}var T=f(i,g),U=T.flat,V=T.showSelectionPalette,W=T.localStorageKey,X=T.theme,Y=T.callbacks,Z=m(O,10),$=!1,_=0,ab=0,bb=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0,jb=0,kb=1,lb=T.palette.slice(0),mb=b.isArray(lb[0])?lb:[lb],nb=T.selectionPalette.slice(0),ob=T.maxSelectionSize,pb="sp-dragging",qb=null,rb=g.ownerDocument,sb=(rb.body,b(g)),tb=!1,ub=b(s,rb).addClass(X),vb=ub.find(".sp-color"),wb=ub.find(".sp-dragger"),xb=ub.find(".sp-hue"),yb=ub.find(".sp-slider"),zb=ub.find(".sp-alpha-inner"),Ab=ub.find(".sp-alpha"),Bb=ub.find(".sp-alpha-handle"),Cb=ub.find(".sp-input"),Db=ub.find(".sp-palette"),Eb=ub.find(".sp-initial"),Fb=ub.find(".sp-cancel"),Gb=ub.find(".sp-choose"),Hb=sb.is("input"),Ib=Hb&&!U,Jb=Ib?b(r).addClass(X).addClass(T.className):b([]),Kb=Ib?Jb:sb,Lb=Jb.find(".sp-preview-inner"),Mb=T.color||Hb&&sb.val(),Nb=!1,Ob=T.preferredFormat,Pb=Ob,Qb=!T.showButtons||T.clickoutFiresChange;n();var Rb={show:C,hide:F,toggle:B,reflow:O,option:Q,enable:R,disable:S,set:function(a){H(a),N()},get:I,destroy:P,container:ub};return Rb.id=o.push(Rb)-1,Rb}function h(a,c){var d=0,e=a.outerWidth(),f=a.outerHeight(),g=c.outerHeight(),h=a[0].ownerDocument,i=h.documentElement,j=i.clientWidth+b(h).scrollLeft(),k=i.clientHeight+b(h).scrollTop(),l=c.offset();return l.top+=g,Math.min(l.left,l.left+e>j&&j>e)?(l.left-=Math.abs(l.left+e-j),a.attr("data-x-position","right")):(l.left-=0,a.attr("data-x-position","left")),Math.min(l.top,l.top+f>k&&k>f)?(l.top-=Math.abs(f+g-d),a.attr("data-y-position","top")):(l.top-=d,a.attr("data-y-position","bottom")),l}function i(){}function j(a){a.stopPropagation()}function k(a,b){var c=Array.prototype.slice,d=c.call(arguments,2);return function(){return a.apply(b,d.concat(c.call(arguments)))}}function l(c,d,e,f){function g(a){a.stopPropagation&&a.stopPropagation(),a.preventDefault&&a.preventDefault(),a.returnValue=!1}function h(a){if(l){if(p&&document.documentMode<9&&!a.button)return j();var b=a.originalEvent.touches,e=b?b[0].pageX:a.pageX,f=b?b[0].pageY:a.pageY,h=Math.max(0,Math.min(e-m.left,o)),i=Math.max(0,Math.min(f-m.top,n));q&&g(a),d.apply(c,[h,i,a])}}function i(a){{var d=a.which?3==a.which:2==a.button;a.originalEvent.touches}d||l||e.apply(c,arguments)!==!1&&(l=!0,n=b(c).height(),o=b(c).width(),m=b(c).offset(),b(k).bind(r),b(k.body).addClass("sp-dragging"),q||h(a),g(a))}function j(){l&&(b(k).unbind(r),b(k.body).removeClass("sp-dragging"),f.apply(c,arguments)),l=!1}d=d||function(){},e=e||function(){},f=f||function(){};var k=c.ownerDocument||document,l=!1,m={},n=0,o=0,q="ontouchstart"in a,r={};r.selectstart=g,r.dragstart=g,r["touchmove mousemove"]=h,r["touchend mouseup"]=j,b(c).bind("touchstart mousedown",i)}function m(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,a.apply(e,f)};c&&clearTimeout(d),(c||!d)&&(d=setTimeout(g,b))}}var n={beforeShow:i,move:i,change:i,show:i,hide:i,color:!1,flat:!1,showInput:!1,showButtons:!0,clickoutFiresChange:!1,showInitial:!1,showPalette:!1,showPaletteOnly:!1,showSelectionPalette:!0,localStorageKey:!1,appendTo:"body",maxSelectionSize:7,cancelText:"cancel",chooseText:"choose",preferredFormat:!1,className:"",showAlpha:!1,theme:"sp-light",palette:["fff","000"],selectionPalette:[],disabled:!1},o=[],p=!!/msie/i.exec(a.navigator.userAgent),q=function(){function a(a,b){return!!~(""+a).indexOf(b)}var b=document.createElement("div"),c=b.style;return c.cssText="background-color:rgba(0,0,0,.5)",a(c.backgroundColor,"rgba")||a(c.backgroundColor,"hsla")}(),r=["
        ","
        ","
        ","
        "].join(""),s=function(){var a="";if(p)for(var b=1;6>=b;b++)a+="
        ";return["
        "].join("")}(),t="spectrum.id";b.fn.spectrum=function(a){if("string"==typeof a){var c=this,d=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=o[b(this).data(t)];if(e){var f=e[a];if(!f)throw new Error("Spectrum: no such method: '"+a+"'");"get"==a?c=e.get():"container"==a?c=e.container:"option"==a?c=e.option.apply(e,d):"destroy"==a?(e.destroy(),b(this).removeData(t)):f.apply(e,d)}}),c}return this.spectrum("destroy").each(function(){var c=g(this,a);b(this).data(t,c.id)})},b.fn.spectrum.load=!0,b.fn.spectrum.loadOpts={},b.fn.spectrum.draggable=l,b.fn.spectrum.defaults=n,b.spectrum={},b.spectrum.localization={},b.spectrum.palettes={},b.fn.spectrum.processNativeColorInputs=function(){var a=b("")[0],c="color"===a.type&&"!"!=a.value;c||b("input[type=color]").spectrum({preferredFormat:"hex6"})},function(){function b(a,d){if(a=a?a:"",d=d||{},"object"==typeof a&&a.hasOwnProperty("_tc_id"))return a;var f=c(a),h=f.r,j=f.g,m=f.b,n=f.a,o=x(100*n)/100,p=d.format||f.format;return 1>h&&(h=x(h)),1>j&&(j=x(j)),1>m&&(m=x(m)),{ok:f.ok,format:p,_tc_id:v++,alpha:n,getAlpha:function(){return n},setAlpha:function(a){n=k(a),o=x(100*n)/100},toHsv:function(){var a=g(h,j,m);return{h:360*a.h,s:a.s,v:a.v,a:n}},toHsvString:function(){var a=g(h,j,m),b=x(360*a.h),c=x(100*a.s),d=x(100*a.v);return 1==n?"hsv("+b+", "+c+"%, "+d+"%)":"hsva("+b+", "+c+"%, "+d+"%, "+o+")"},toHsl:function(){var a=e(h,j,m);return{h:360*a.h,s:a.s,l:a.l,a:n}},toHslString:function(){var a=e(h,j,m),b=x(360*a.h),c=x(100*a.s),d=x(100*a.l);return 1==n?"hsl("+b+", "+c+"%, "+d+"%)":"hsla("+b+", "+c+"%, "+d+"%, "+o+")"},toHex:function(a){return i(h,j,m,a)},toHexString:function(a){return"#"+i(h,j,m,a)},toRgb:function(){return{r:x(h),g:x(j),b:x(m),a:n}},toRgbString:function(){return 1==n?"rgb("+x(h)+", "+x(j)+", "+x(m)+")":"rgba("+x(h)+", "+x(j)+", "+x(m)+", "+o+")"},toPercentageRgb:function(){return{r:x(100*l(h,255))+"%",g:x(100*l(j,255))+"%",b:x(100*l(m,255))+"%",a:n}},toPercentageRgbString:function(){return 1==n?"rgb("+x(100*l(h,255))+"%, "+x(100*l(j,255))+"%, "+x(100*l(m,255))+"%)":"rgba("+x(100*l(h,255))+"%, "+x(100*l(j,255))+"%, "+x(100*l(m,255))+"%, "+o+")"},toName:function(){return 0===n?"transparent":C[i(h,j,m,!0)]||!1},toFilter:function(a){var c=i(h,j,m),e=c,f=Math.round(255*parseFloat(n)).toString(16),g=f,k=d&&d.gradientType?"GradientType = 1, ":"";if(a){var l=b(a);e=l.toHex(),g=Math.round(255*parseFloat(l.alpha)).toString(16)}return"progid:DXImageTransform.Microsoft.gradient("+k+"startColorstr=#"+q(f)+c+",endColorstr=#"+q(g)+e+")"},toString:function(a){var b=!!a;a=a||this.format;var c=!1,d=!b&&1>n&&n>0,e=d&&("hex"===a||"hex6"===a||"hex3"===a||"name"===a);return"rgb"===a&&(c=this.toRgbString()),"prgb"===a&&(c=this.toPercentageRgbString()),("hex"===a||"hex6"===a)&&(c=this.toHexString()),"hex3"===a&&(c=this.toHexString(!0)),"name"===a&&(c=this.toName()),"hsl"===a&&(c=this.toHslString()),"hsv"===a&&(c=this.toHsvString()),e?this.toRgbString():c||this.toHexString()}}}function c(a){var b={r:0,g:0,b:0},c=1,e=!1,g=!1;return"string"==typeof a&&(a=s(a)),"object"==typeof a&&(a.hasOwnProperty("r")&&a.hasOwnProperty("g")&&a.hasOwnProperty("b")?(b=d(a.r,a.g,a.b),e=!0,g="%"===String(a.r).substr(-1)?"prgb":"rgb"):a.hasOwnProperty("h")&&a.hasOwnProperty("s")&&a.hasOwnProperty("v")?(a.s=r(a.s),a.v=r(a.v),b=h(a.h,a.s,a.v),e=!0,g="hsv"):a.hasOwnProperty("h")&&a.hasOwnProperty("s")&&a.hasOwnProperty("l")&&(a.s=r(a.s),a.l=r(a.l),b=f(a.h,a.s,a.l),e=!0,g="hsl"),a.hasOwnProperty("a")&&(c=a.a)),c=k(c),{ok:e,format:a.format||g,r:y(255,z(b.r,0)),g:y(255,z(b.g,0)),b:y(255,z(b.b,0)),a:c}}function d(a,b,c){return{r:255*l(a,255),g:255*l(b,255),b:255*l(c,255)}}function e(a,b,c){a=l(a,255),b=l(b,255),c=l(c,255);var d,e,f=z(a,b,c),g=y(a,b,c),h=(f+g)/2;if(f==g)d=e=0;else{var i=f-g;switch(e=h>.5?i/(2-f-g):i/(f+g),f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return{h:d,s:e,l:h}}function f(a,b,c){function d(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+(b-a)*(2/3-c)*6:a}var e,f,g;if(a=l(a,360),b=l(b,100),c=l(c,100),0===b)e=f=g=c;else{var h=.5>c?c*(1+b):c+b-c*b,i=2*c-h;e=d(i,h,a+1/3),f=d(i,h,a),g=d(i,h,a-1/3)}return{r:255*e,g:255*f,b:255*g}}function g(a,b,c){a=l(a,255),b=l(b,255),c=l(c,255);var d,e,f=z(a,b,c),g=y(a,b,c),h=f,i=f-g;if(e=0===f?0:i/f,f==g)d=0;else{switch(f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return{h:d,s:e,v:h}}function h(a,b,c){a=6*l(a,360),b=l(b,100),c=l(c,100);var d=w.floor(a),e=a-d,f=c*(1-b),g=c*(1-e*b),h=c*(1-(1-e)*b),i=d%6,j=[c,g,f,f,h,c][i],k=[h,c,c,g,f,f][i],m=[f,f,h,c,c,g][i];return{r:255*j,g:255*k,b:255*m}}function i(a,b,c,d){var e=[q(x(a).toString(16)),q(x(b).toString(16)),q(x(c).toString(16))];return d&&e[0].charAt(0)==e[0].charAt(1)&&e[1].charAt(0)==e[1].charAt(1)&&e[2].charAt(0)==e[2].charAt(1)?e[0].charAt(0)+e[1].charAt(0)+e[2].charAt(0):e.join("")}function j(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[a[c]]=c);return b}function k(a){return a=parseFloat(a),(isNaN(a)||0>a||a>1)&&(a=1),a}function l(a,b){o(a)&&(a="100%");var c=p(a);return a=y(b,z(0,parseFloat(a))),c&&(a=parseInt(a*b,10)/100),w.abs(a-b)<1e-6?1:a%b/parseFloat(b)}function m(a){return y(1,z(0,a))}function n(a){return parseInt(a,16)}function o(a){return"string"==typeof a&&-1!=a.indexOf(".")&&1===parseFloat(a)}function p(a){return"string"==typeof a&&-1!=a.indexOf("%")}function q(a){return 1==a.length?"0"+a:""+a}function r(a){return 1>=a&&(a=100*a+"%"),a}function s(a){a=a.replace(t,"").replace(u,"").toLowerCase();var b=!1;if(B[a])a=B[a],b=!0;else if("transparent"==a)return{r:0,g:0,b:0,a:0,format:"name"};var c;return(c=D.rgb.exec(a))?{r:c[1],g:c[2],b:c[3]}:(c=D.rgba.exec(a))?{r:c[1],g:c[2],b:c[3],a:c[4]}:(c=D.hsl.exec(a))?{h:c[1],s:c[2],l:c[3]}:(c=D.hsla.exec(a))?{h:c[1],s:c[2],l:c[3],a:c[4]}:(c=D.hsv.exec(a))?{h:c[1],s:c[2],v:c[3]}:(c=D.hex6.exec(a))?{r:n(c[1]),g:n(c[2]),b:n(c[3]),format:b?"name":"hex"}:(c=D.hex3.exec(a))?{r:n(c[1]+""+c[1]),g:n(c[2]+""+c[2]),b:n(c[3]+""+c[3]),format:b?"name":"hex"}:!1}var t=/^[\s,#]+/,u=/\s+$/,v=0,w=Math,x=w.round,y=w.min,z=w.max,A=w.random;b.fromRatio=function(a,c){if("object"==typeof a){var d={};for(var e in a)a.hasOwnProperty(e)&&(d[e]="a"===e?a[e]:r(a[e]));a=d}return b(a,c)},b.equals=function(a,c){return a&&c?b(a).toRgbString()==b(c).toRgbString():!1},b.random=function(){return b.fromRatio({r:A(),g:A(),b:A()})},b.desaturate=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.s-=c/100,d.s=m(d.s),b(d)},b.saturate=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.s+=c/100,d.s=m(d.s),b(d)},b.greyscale=function(a){return b.desaturate(a,100)},b.lighten=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.l+=c/100,d.l=m(d.l),b(d)},b.darken=function(a,c){c=0===c?0:c||10;var d=b(a).toHsl();return d.l-=c/100,d.l=m(d.l),b(d)},b.complement=function(a){var c=b(a).toHsl();return c.h=(c.h+180)%360,b(c)},b.triad=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+120)%360,s:c.s,l:c.l}),b({h:(d+240)%360,s:c.s,l:c.l})]},b.tetrad=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+90)%360,s:c.s,l:c.l}),b({h:(d+180)%360,s:c.s,l:c.l}),b({h:(d+270)%360,s:c.s,l:c.l})]},b.splitcomplement=function(a){var c=b(a).toHsl(),d=c.h;return[b(a),b({h:(d+72)%360,s:c.s,l:c.l}),b({h:(d+216)%360,s:c.s,l:c.l})]},b.analogous=function(a,c,d){c=c||6,d=d||30;var e=b(a).toHsl(),f=360/d,g=[b(a)];for(e.h=(e.h-(f*c>>1)+720)%360;--c;)e.h=(e.h+f)%360,g.push(b(e));return g},b.monochromatic=function(a,c){c=c||6;for(var d=b(a).toHsv(),e=d.h,f=d.s,g=d.v,h=[],i=1/c;c--;)h.push(b({h:e,s:f,v:g})),g=(g+i)%1;return h},b.readability=function(a,c){var d=b(a).toRgb(),e=b(c).toRgb(),f=(299*d.r+587*d.g+114*d.b)/1e3,g=(299*e.r+587*e.g+114*e.b)/1e3,h=Math.max(d.r,e.r)-Math.min(d.r,e.r)+Math.max(d.g,e.g)-Math.min(d.g,e.g)+Math.max(d.b,e.b)-Math.min(d.b,e.b);return{brightness:Math.abs(f-g),color:h}},b.readable=function(a,c){var d=b.readability(a,c);return d.brightness>125&&d.color>500},b.mostReadable=function(a,c){for(var d=null,e=0,f=!1,g=0;g125&&h.color>500,j=3*(h.brightness/125)+h.color/500;(i&&!f||i&&f&&j>e||!i&&!f&&j>e)&&(f=i,e=j,d=b(c[g]))}return d};var B=b.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"},C=b.hexNames=j(B),D=function(){var a="[-\\+]?\\d+%?",b="[-\\+]?\\d*\\.\\d+%?",c="(?:"+b+")|(?:"+a+")",d="[\\s|\\(]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")\\s*\\)?",e="[\\s|\\(]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")[,|\\s]+("+c+")\\s*\\)?";return{rgb:new RegExp("rgb"+d),rgba:new RegExp("rgba"+e),hsl:new RegExp("hsl"+d),hsla:new RegExp("hsla"+e),hsv:new RegExp("hsv"+d),hex3:/^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/}}();a.tinycolor=b}();var u=a.tinycolor;b(function(){b.fn.spectrum.load&&b.fn.spectrum.processNativeColorInputs()})}(window,jQuery),function(){var a=$.namespace("pskl.rendering");a.DrawingLoop=function(){this.requestAnimationFrame=this.getRequestAnimationFrameShim_(),this.isRunning=!1,this.previousTime=0,this.callbacks=[]},a.DrawingLoop.prototype.addCallback=function(a,b,c){var d={fn:a,scope:b,args:c};return this.callbacks.push(d),d},a.DrawingLoop.prototype.removeCallback=function(a){var b=this.callbacks.indexOf(a);-1!=b&&this.callbacks.splice(b,1)},a.DrawingLoop.prototype.start=function(){this.isRunning=!0,this.loop_()},a.DrawingLoop.prototype.loop_=function(){var a=Date.now(),b=a-this.previousTime;this.executeCallbacks_(b),this.previousTime=a,this.requestAnimationFrame.call(window,this.loop_.bind(this))},a.DrawingLoop.prototype.executeCallbacks_=function(a){for(var b=0;bd;d++){for(var e=[],f=0;b>f;f++)e.push(Constants.TRANSPARENT_COLOR);c[d]=e}return c},a.Frame.createEmptyFromFrame=function(b){return new a.Frame(b.getWidth(),b.getHeight())},a.Frame.prototype.clone=function(){var b=new a.Frame(this.width,this.height);return b.setPixels(this.getPixels()),b},a.Frame.prototype.getPixels=function(){return this.clonePixels_(this.pixels)},a.Frame.prototype.setPixels=function(a){this.pixels=this.clonePixels_(a),this.version++},a.Frame.prototype.clear=function(){var b=a.Frame.createEmptyPixelGrid_(this.getWidth(),this.getHeight());this.setPixels(b)},a.Frame.prototype.clonePixels_=function(a){for(var b=[],c=0;cd;d++)for(var e=0;c>e;e++)a(this.pixels[d][e],d,e,this)},a.Frame.prototype.getWidth=function(){return this.width},a.Frame.prototype.getHeight=function(){return this.height},a.Frame.prototype.containsPixel=function(a,b){return a>=0&&b>=0&&a0&&a[0].length()>0))throw"Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument";var d=a[0].getFrameAt(0);return c=new pskl.model.Piskel(d.getWidth(),d.getHeight(),b),a.forEach(c.addLayer.bind(c)),c},a.Piskel.prototype.getLayers=function(){return this.layers},a.Piskel.prototype.getHeight=function(){return this.height},a.Piskel.prototype.getWidth=function(){return this.width},a.Piskel.prototype.getLayers=function(){return this.layers},a.Piskel.prototype.getLayerAt=function(a){return this.layers[a]},a.Piskel.prototype.getLayersByName=function(a){return this.layers.filter(function(b){return b.getName()==a})},a.Piskel.prototype.addLayer=function(a){this.layers.push(a)},a.Piskel.prototype.moveLayerUp=function(a){var b=this.layers.indexOf(a);b>-1&&b0&&(this.layers[b]=this.layers[b-1],this.layers[b-1]=a)},a.Piskel.prototype.removeLayer=function(a){var b=this.layers.indexOf(a);-1!=b&&this.layers.splice(b,1)},a.Piskel.prototype.removeLayerAt=function(a){this.layers.splice(a,1)},a.Piskel.prototype.getDescriptor=function(){return this.descriptor},a.Piskel.prototype.setDescriptor=function(a){this.descriptor=a;$(".piskel-name").html(this.descriptor.name)},a.Piskel.prototype.getHash=function(){return this.layers.map(function(a){return a.getHash()}).join("-")}}(),function(){var a=$.namespace("pskl.selection"),b={PASTE:"REPLAY_PASTE",ERASE:"REPLAY_ERASE"};a.SelectionManager=function(a){this.piskelController=a,this.currentSelection=null},a.SelectionManager.prototype.init=function(){$.subscribe(Events.SELECTION_CREATED,$.proxy(this.onSelectionCreated_,this)),$.subscribe(Events.SELECTION_DISMISSED,$.proxy(this.onSelectionDismissed_,this)),$.subscribe(Events.SELECTION_MOVE_REQUEST,$.proxy(this.onSelectionMoved_,this)),pskl.app.shortcutService.addShortcut("ctrl+V",this.paste.bind(this)),pskl.app.shortcutService.addShortcut("ctrl+X",this.cut.bind(this)),pskl.app.shortcutService.addShortcut("ctrl+C",this.copy.bind(this)),pskl.app.shortcutService.addShortcut("del",this.erase.bind(this)),pskl.app.shortcutService.addShortcut("back",this.onBackPressed_.bind(this)),$.subscribe(Events.TOOL_SELECTED,$.proxy(this.onToolSelected_,this))},a.SelectionManager.prototype.cleanSelection_=function(){this.currentSelection&&(this.currentSelection.reset(),this.currentSelection=null)},a.SelectionManager.prototype.onToolSelected_=function(a,b){var c=b instanceof pskl.drawingtools.BaseSelect;c||this.cleanSelection_()},a.SelectionManager.prototype.onSelectionDismissed_=function(){this.cleanSelection_()},a.SelectionManager.prototype.onBackPressed_=function(){return this.currentSelection?void this.erase():!0},a.SelectionManager.prototype.erase=function(){for(var a=this.currentSelection.pixels,c=this.piskelController.getCurrentFrame(),d=0,e=a.length;e>d;d++)c.setPixel(a[d].col,a[d].row,Constants.TRANSPARENT_COLOR);$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY,scope:this,replay:{type:b.ERASE,pixels:JSON.parse(JSON.stringify(a.slice(0)))}})},a.SelectionManager.prototype.cut=function(){if(!this.currentSelection)throw"Bad state for CUT callback in SelectionManager";this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame()),this.erase()},a.SelectionManager.prototype.paste=function(){if(this.currentSelection&&this.currentSelection.hasPastedContent){var a=this.currentSelection.pixels,b=a.filter(function(a){return a.color!==Constants.TRANSPARENT_COLOR});this.pastePixels(b)}},a.SelectionManager.prototype.pastePixels=function(a){var c=this.piskelController.getCurrentFrame();a.forEach(function(a){c.setPixel(a.col,a.row,a.color)}),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY,scope:this,replay:{type:b.PASTE,pixels:JSON.parse(JSON.stringify(a.slice(0)))}})},a.SelectionManager.prototype.replay=function(a,c){var d=c.pixels;d.forEach(function(d){var e=c.type===b.PASTE?d.color:Constants.TRANSPARENT_COLOR;a.setPixel(d.col,d.row,e)})},a.SelectionManager.prototype.copy=function(){if(!this.currentSelection||!this.piskelController.getCurrentFrame())throw"Bad state for CUT callback in SelectionManager";this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame())},a.SelectionManager.prototype.onSelectionCreated_=function(a,b){if(!b)throw"No selection set in SelectionManager";this.currentSelection=b},a.SelectionManager.prototype.onSelectionMoved_=function(a,b,c){if(!this.currentSelection)throw"Bad state: No currentSelection set when trying to move it in SelectionManager";this.currentSelection.move(b,c)}}(),function(){var a=$.namespace("pskl.selection");a.BaseSelection=function(){this.reset()},a.BaseSelection.prototype.reset=function(){this.pixels=[],this.hasPastedContent=!1},a.BaseSelection.prototype.move=function(a,b){for(var c,d=[],e=0,f=this.pixels.length;f>e;e++)c=this.pixels[e],c.col+=a,c.row+=b,d.push(c); -this.pixels=d},a.BaseSelection.prototype.fillSelectionFromFrame=function(a){this.pixels.forEach(function(b){b.color=a.getPixel(b.col,b.row)}),this.hasPastedContent=!0}}(),function(){var a=$.namespace("pskl.selection");a.RectangularSelection=function(a,b,c,d){this.pixels=pskl.PixelUtils.getRectanglePixels(a,b,c,d)},pskl.utils.inherit(a.RectangularSelection,a.BaseSelection)}(),function(){var a=$.namespace("pskl.selection");a.ShapeSelection=function(a){this.pixels=a},pskl.utils.inherit(a.ShapeSelection,a.BaseSelection)}(),function(){var a=$.namespace("pskl.rendering");a.AbstractRenderer=function(){},a.AbstractRenderer.prototype.clear=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.render=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getCoordinates=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setGridWidth=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getGridWidth=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setZoom=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getZoom=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setOffset=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getOffset=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.setDisplaySize=Constants.ABSTRACT_FUNCTION,a.AbstractRenderer.prototype.getDisplaySize=Constants.ABSTRACT_FUNCTION}(),function(){var a=$.namespace("pskl.rendering");a.CompositeRenderer=function(){this.renderers=[]},pskl.utils.inherit(pskl.rendering.CompositeRenderer,pskl.rendering.AbstractRenderer),a.CompositeRenderer.prototype.add=function(a){return this.renderers.push(a),this},a.CompositeRenderer.prototype.clear=function(){this.renderers.forEach(function(a){a.clear()})},a.CompositeRenderer.prototype.setZoom=function(a){this.renderers.forEach(function(b){b.setZoom(a)})},a.CompositeRenderer.prototype.getZoom=function(){return this.getSampleRenderer_().getZoom()},a.CompositeRenderer.prototype.setDisplaySize=function(a,b){this.renderers.forEach(function(c){c.setDisplaySize(a,b)})},a.CompositeRenderer.prototype.getDisplaySize=function(){return this.getSampleRenderer_().getDisplaySize()},a.CompositeRenderer.prototype.setOffset=function(a,b){this.renderers.forEach(function(c){c.setOffset(a,b)})},a.CompositeRenderer.prototype.getOffset=function(){return this.getSampleRenderer_().getOffset()},a.CompositeRenderer.prototype.setGridWidth=function(a){this.renderers.forEach(function(b){b.setGridWidth(a)})},a.CompositeRenderer.prototype.getGridWidth=function(){return this.getSampleRenderer_().getGridWidth()},a.CompositeRenderer.prototype.getSampleRenderer_=function(){if(this.renderers.length>0)return this.renderers[0];throw"Renderer manager is empty"}}(),function(){var a=$.namespace("pskl.rendering.layer");a.LayersRenderer=function(a,b,c){pskl.rendering.CompositeRenderer.call(this),this.piskelController=c,this.belowRenderer=new pskl.rendering.frame.FrameRenderer(a,b,["layers-canvas","layers-below-canvas"]),this.aboveRenderer=new pskl.rendering.frame.FrameRenderer(a,b,["layers-canvas","layers-above-canvas"]),this.add(this.belowRenderer),this.add(this.aboveRenderer),this.serializedRendering="",$.subscribe(Events.PISKEL_RESET,this.flush.bind(this))},pskl.utils.inherit(pskl.rendering.layer.LayersRenderer,pskl.rendering.CompositeRenderer),a.LayersRenderer.prototype.render=function(){var a=this.getOffset(),b=this.getDisplaySize(),c=this.piskelController.getLayers(),d=this.piskelController.getCurrentFrameIndex(),e=this.piskelController.getCurrentLayerIndex(),f=c.slice(0,e),g=c.slice(e+1,c.length),h=[this.getZoom(),this.getGridWidth(),a.x,a.y,b.width,b.height,this.getHashForLayersAt_(d,f),this.getHashForLayersAt_(d,g),c.length].join("-");if(this.serializedRendering!=h){if(this.serializedRendering=h,this.clear(),f.length>0){var i=this.getFrameForLayersAt_(d,f);this.belowRenderer.render(i)}if(g.length>0){var j=this.getFrameForLayersAt_(d,g);this.aboveRenderer.render(j)}}},a.LayersRenderer.prototype.setDisplaySize=function(a,b){var c=this.getDisplaySize();(c.width!==a||c.height!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.LayersRenderer.prototype.getFrameForLayersAt_=function(a,b){var c=b.map(function(b){return b.getFrameAt(a)});return pskl.utils.FrameUtils.merge(c)},a.LayersRenderer.prototype.getHashForLayersAt_=function(a,b){var c=b.map(function(b){return b.getFrameAt(a).getHash()});return c.join("-")},a.LayersRenderer.prototype.flush=function(){this.serializedRendering=""}}(),function(){var a=$.namespace("pskl.rendering.frame");a.FrameRenderer=function(a,b,c){if(this.defaultRenderingOptions={supportGridRendering:!1,zoom:1},b=$.extend(!0,{},this.defaultRenderingOptions,b),void 0===a)throw"Bad FrameRenderer initialization. undefined.";if(isNaN(b.zoom))throw"Bad FrameRenderer initialization. not well defined.";this.container=a,this.zoom=b.zoom,this.offset={x:0,y:0},this.margin={x:0,y:0},this.supportGridRendering=b.supportGridRendering,this.classes=c||[],this.classes.push("canvas"),this.canvas=null,this.displayCanvas=null,this.setDisplaySize(b.width,b.height),this.setGridWidth(pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH)),$.subscribe(Events.USER_SETTINGS_CHANGED,this.onUserSettingsChange_.bind(this))},pskl.utils.inherit(pskl.rendering.frame.FrameRenderer,pskl.rendering.AbstractRenderer),a.FrameRenderer.prototype.render=function(a){a&&(this.clear(),this.renderFrame_(a))},a.FrameRenderer.prototype.clear=function(){pskl.CanvasUtils.clear(this.canvas),pskl.CanvasUtils.clear(this.displayCanvas)},a.FrameRenderer.prototype.setZoom=function(a){if(a>Constants.MINIMUM_ZOOM){var b=this.offset.x+this.displayWidth/(2*this.zoom),c=this.offset.y+this.displayHeight/(2*this.zoom);this.zoom=a,this.setOffset(b-this.displayWidth/(2*this.zoom),c-this.displayHeight/(2*this.zoom))}},a.FrameRenderer.prototype.getZoom=function(){return this.zoom},a.FrameRenderer.prototype.setDisplaySize=function(a,b){this.displayWidth=a,this.displayHeight=b,this.displayCanvas&&($(this.displayCanvas).remove(),this.displayCanvas=null),this.createDisplayCanvas_()},a.FrameRenderer.prototype.getDisplaySize=function(){return{height:this.displayHeight,width:this.displayWidth}},a.FrameRenderer.prototype.getOffset=function(){return{x:this.offset.x,y:this.offset.y}},a.FrameRenderer.prototype.setOffset=function(a,b){var c=pskl.app.piskelController.getWidth(),d=pskl.app.piskelController.getHeight(),e=c-this.displayWidth/this.zoom;a=pskl.utils.Math.minmax(a,0,e);var f=d-this.displayHeight/this.zoom;b=pskl.utils.Math.minmax(b,0,f),this.offset.x=a,this.offset.y=b},a.FrameRenderer.prototype.setGridWidth=function(a){this.gridWidth_=a},a.FrameRenderer.prototype.getGridWidth=function(){return this.supportGridRendering?this.gridWidth_:0},a.FrameRenderer.prototype.updateMargins_=function(a){var b=this.displayWidth-this.zoom*a.getWidth();this.margin.x=Math.max(0,b)/2;var c=this.displayHeight-this.zoom*a.getHeight();this.margin.y=Math.max(0,c)/2},a.FrameRenderer.prototype.createDisplayCanvas_=function(){var a=this.displayHeight,b=this.displayWidth;this.displayCanvas=pskl.CanvasUtils.createCanvas(b,a,this.classes),pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas),this.container.append(this.displayCanvas)},a.FrameRenderer.prototype.onUserSettingsChange_=function(a,b,c){b==pskl.UserSettings.GRID_WIDTH&&this.setGridWidth(c)},a.FrameRenderer.prototype.renderPixel_=function(a,b,c,d){a!=Constants.TRANSPARENT_COLOR&&(d.fillStyle=a,d.fillRect(b,c,1,1))},a.FrameRenderer.prototype.getCoordinates=function(a,b){var c=this.container.offset();a-=c.left,b-=c.top,a-=this.margin.x,b-=this.margin.y;var d=this.zoom;return a+=this.offset.x*d,b+=this.offset.y*d,{x:Math.floor(a/d),y:Math.floor(b/d)}},a.FrameRenderer.prototype.reverseCoordinates=function(a,b){var c=this.zoom;a*=c,b*=c,a-=this.offset.x*c,b-=this.offset.y*c,a+=this.margin.x,b+=this.margin.y;var d=this.container.offset();return a+=d.left,b+=d.top,{x:a+c/2,y:b+c/2}},a.FrameRenderer.prototype.renderFrame_=function(a){this.canvas&&a.getWidth()==this.canvas.width&&a.getHeight()==this.canvas.height||(this.canvas=pskl.CanvasUtils.createCanvas(a.getWidth(),a.getHeight()));for(var b=this.canvas.getContext("2d"),c=0,d=a.getWidth();d>c;c++)for(var e=0,f=a.getHeight();f>e;e++){var g=a.getPixel(c,e);this.renderPixel_(g,c,e,b)}this.updateMargins_(a);var h=this.displayCanvas.getContext("2d");h.save(),this.canvas.width*this.zoom0;if(k||i){var l=pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas,this.zoom,j);h.drawImage(l,0,0)}else h.scale(this.zoom,this.zoom),h.drawImage(this.canvas,0,0);h.restore()}}(),function(){var a=$.namespace("pskl.rendering");a.OnionSkinRenderer=function(a,b,c){pskl.rendering.CompositeRenderer.call(this),this.piskelController=c,this.renderer=new pskl.rendering.frame.FrameRenderer(a,b,["onion-skin-canvas"]),this.add(this.renderer),this.serializedRendering=""},pskl.utils.inherit(pskl.rendering.OnionSkinRenderer,pskl.rendering.CompositeRenderer),a.OnionSkinRenderer.prototype.render=function(){var a=this.getOffset(),b=this.getDisplaySize(),c=this.piskelController.getLayers(),d=this.piskelController.getCurrentFrameIndex(),e=[];this.addFrameAtIndexToArray_(d-1,e),this.addFrameAtIndexToArray_(d+1,e);var f=[this.getZoom(),this.getGridWidth(),a.x,a.y,b.width,b.height,e.map(function(a){return a.getHash()}).join("-"),c.length].join("-");if(this.serializedRendering!=f&&(this.serializedRendering=f,e.length>0)){this.clear();var g=pskl.utils.FrameUtils.merge(e);this.renderer.render(g)}},a.OnionSkinRenderer.prototype.addFrameAtIndexToArray_=function(a,b){var c=this.piskelController.getCurrentLayer();this.piskelController.hasFrameAt(a)&&b.push(c.getFrameAt(a))},a.OnionSkinRenderer.prototype.setDisplaySize=function(a,b){var c=this.getDisplaySize();(c.width!==a||c.height!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.OnionSkinRenderer.prototype.flush=function(){this.serializedRendering=""}}(),function(){var a=$.namespace("pskl.rendering.frame");a.TiledFrameRenderer=function(a,b){this.container=a,this.setZoom(b),this.displayContainer=document.createElement("div"),this.displayContainer.classList.add("tiled-frame-container"),a.get(0).appendChild(this.displayContainer),this.cachedFrameProcessor=new pskl.model.frame.CachedFrameProcessor,this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this))},a.TiledFrameRenderer.prototype.frameToDataUrl_=function(a){var b=new pskl.utils.FrameUtils.toImage(a,this.zoom);return b.toDataURL("image/png")},a.TiledFrameRenderer.prototype.render=function(a){var b=this.cachedFrameProcessor.get(a,this.zoom);this.displayContainer.style.backgroundImage="url("+b+")"},a.TiledFrameRenderer.prototype.show=function(){this.displayContainer&&(this.displayContainer.style.display="block")},a.TiledFrameRenderer.prototype.setZoom=function(a){this.zoom=a},a.TiledFrameRenderer.prototype.getZoom=function(){return this.zoom}}(),function(){var a=$.namespace("pskl.rendering.frame");a.CachedFrameRenderer=function(a,b,c){pskl.rendering.frame.FrameRenderer.call(this,a,b,c),this.serializedFrame=""},pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer,pskl.rendering.frame.FrameRenderer),a.CachedFrameRenderer.prototype.setDisplaySize=function(a,b){(this.displayWidth!==a||this.displayHeight!==b)&&this.superclass.setDisplaySize.call(this,a,b)},a.CachedFrameRenderer.prototype.render=function(a){var b=this.getOffset(),c=this.getDisplaySize(),d=[this.getZoom(),this.getGridWidth(),b.x,b.y,c.width,c.height,a.getHash()].join("-");this.serializedFrame!=d&&(this.serializedFrame=d,this.superclass.render.call(this,a))}}(),function(){var a=$.namespace("pskl.rendering");a.CanvasRenderer=function(a,b){this.frame=a,this.zoom=b,this.transparentColor_="white"},a.CanvasRenderer.prototype.drawTransparentAs=function(a){this.transparentColor_=a},a.CanvasRenderer.prototype.render=function(){var a=this.createCanvas_(),b=a.getContext("2d");this.frame.forEachPixel(function(a,c,d){this.renderPixel_(a,c,d,b)}.bind(this));var c=this.createCanvas_(this.zoom),d=c.getContext("2d");return pskl.CanvasUtils.disableImageSmoothing(c),d.scale(this.zoom,this.zoom),d.drawImage(a,0,0),c},a.CanvasRenderer.prototype.renderPixel_=function(a,b,c,d){a==Constants.TRANSPARENT_COLOR&&(a=this.transparentColor_),d.fillStyle=a,d.fillRect(b,c,1,1)},a.CanvasRenderer.prototype.createCanvas_=function(a){a=a||1;var b=this.frame.getWidth()*a,c=this.frame.getHeight()*a;return pskl.CanvasUtils.createCanvas(b,c)}}(),function(){var a=$.namespace("pskl.rendering");a.FramesheetRenderer=function(a){if(!(a.length>0))throw"FramesheetRenderer : Invalid argument : frames is empty";this.frames=a},a.FramesheetRenderer.prototype.renderAsCanvas=function(){for(var a=this.createCanvas_(),b=0;b=a&&this.currentFrameIndex>0&&this.setCurrentFrameIndex(this.currentFrameIndex-1)},a.PiskelController.prototype.duplicateCurrentFrame=function(){this.duplicateFrameAt(this.currentFrameIndex)},a.PiskelController.prototype.duplicateFrameAt=function(a){this.getLayers().forEach(function(b){b.duplicateFrameAt(a)}),this.setCurrentFrameIndex(a+1)},a.PiskelController.prototype.moveFrame=function(a,b){this.getLayers().forEach(function(c){c.moveFrame(a,b)})},a.PiskelController.prototype.getFrameCount=function(){var a=this.piskel.getLayerAt(0);return a.length()},a.PiskelController.prototype.setCurrentFrameIndex=function(a){this.hasFrameAt(a)?this.currentFrameIndex=a:window.console.error("Could not set current frame index to "+a)},a.PiskelController.prototype.selectNextFrame=function(){var a=this.currentFrameIndex+1;a=0&&this.setCurrentFrameIndex(a)},a.PiskelController.prototype.setCurrentLayerIndex=function(a){this.hasLayerAt(a)?this.currentLayerIndex=a:window.console.error("Could not set current layer index to "+a)},a.PiskelController.prototype.selectLayer=function(a){var b=this.getLayers().indexOf(a);-1!=b&&this.setCurrentLayerIndex(b)},a.PiskelController.prototype.renameLayerAt=function(a,b){var c=this.getLayerByIndex(a);c&&c.setName(b)},a.PiskelController.prototype.generateLayerName_=function(){for(var a="Layer "+this.layerIdCounter;this.hasLayerForName_(a);)this.layerIdCounter++,a="Layer "+this.layerIdCounter;return a},a.PiskelController.prototype.createLayer=function(a){if(a||(a=this.generateLayerName_()),this.hasLayerForName_(a))throw"Layer name should be unique";for(var b=new pskl.model.Layer(a),c=0;c0},a.PiskelController.prototype.moveLayerUp=function(){var a=this.getCurrentLayer();this.piskel.moveLayerUp(a),this.selectLayer(a)},a.PiskelController.prototype.moveLayerDown=function(){var a=this.getCurrentLayer();this.piskel.moveLayerDown(a),this.selectLayer(a)},a.PiskelController.prototype.removeLayerAt=function(a){if(this.getLayers().length>1){var b=this.getLayerAt(a);b&&(this.piskel.removeLayer(b),this.setCurrentLayerIndex(0))}},a.PiskelController.prototype.serialize=function(a){return pskl.utils.Serializer.serializePiskel(this.piskel,a)}}(),function(){var a=$.namespace("pskl.controller.piskel");a.PublicPiskelController=function(a){this.piskelController=a,pskl.utils.wrap(this,this.piskelController)},a.PublicPiskelController.prototype.init=function(){pskl.app.shortcutService.addShortcut("up",this.selectPreviousFrame.bind(this)),pskl.app.shortcutService.addShortcut("down",this.selectNextFrame.bind(this)),pskl.app.shortcutService.addShortcut("n",this.addFrameAtCurrentIndex.bind(this)),pskl.app.shortcutService.addShortcut("shift+n",this.duplicateCurrentFrame.bind(this))},a.PublicPiskelController.prototype.setPiskel=function(a,b){this.piskelController.setPiskel(a,b),$.publish(Events.FRAME_SIZE_CHANGED),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})},a.PublicPiskelController.prototype.addFrame=function(){this.addFrameAt(this.getFrameCount())},a.PublicPiskelController.prototype.addFrameAtCurrentIndex=function(){this.addFrameAt(this.getCurrentFrameIndex())},a.PublicPiskelController.prototype.addFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.addFrameAt,[a]),this.piskelController.addFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.removeFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.removeFrameAt,[a]),this.piskelController.removeFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.duplicateCurrentFrame=function(){this.duplicateFrameAt(this.getCurrentFrameIndex())},a.PublicPiskelController.prototype.replay=function(a,b){b.fn.apply(this.piskelController,b.args)},a.PublicPiskelController.prototype.duplicateFrameAt=function(a){this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt,[a]),this.piskelController.duplicateFrameAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveFrame=function(a,b){this.raiseSaveStateEvent_(this.piskelController.moveFrame,[a,b]),this.piskelController.moveFrame(a,b),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.setCurrentFrameIndex=function(a){this.piskelController.setCurrentFrameIndex(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectNextFrame=function(){this.piskelController.selectNextFrame(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectPreviousFrame=function(){this.piskelController.selectPreviousFrame(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.setCurrentLayerIndex=function(a){this.piskelController.setCurrentLayerIndex(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.selectLayer=function(a){this.piskelController.selectLayer(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.renameLayerAt=function(a,b){this.raiseSaveStateEvent_(this.piskelController.renameLayerAt,[a,b]),this.piskelController.renameLayerAt(a,b)},a.PublicPiskelController.prototype.createLayer=function(a){this.raiseSaveStateEvent_(this.piskelController.createLayer,[a]),this.piskelController.createLayer(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveLayerUp=function(){this.raiseSaveStateEvent_(this.piskelController.moveLayerUp,[]),this.piskelController.moveLayerUp(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.moveLayerDown=function(){this.raiseSaveStateEvent_(this.piskelController.moveLayerDown,[]),this.piskelController.moveLayerDown(),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.removeCurrentLayer=function(){var a=this.getCurrentLayerIndex();this.raiseSaveStateEvent_(this.piskelController.removeLayerAt,[a]),this.piskelController.removeLayerAt(a),$.publish(Events.PISKEL_RESET)},a.PublicPiskelController.prototype.getCurrentLayerIndex=function(){return this.piskelController.getCurrentLayerIndex()},a.PublicPiskelController.prototype.getCurrentFrameIndex=function(){return this.piskelController.currentFrameIndex},a.PublicPiskelController.prototype.getPiskel=function(){return this.piskelController.piskel},a.PublicPiskelController.prototype.raiseSaveStateEvent_=function(a,b){$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.REPLAY_NO_SNAPSHOT,scope:this,replay:{fn:a,args:b}})}}(),function(){var a=$.namespace("pskl.controller");a.CursorCoordinatesController=function(a){this.piskelController=a,this.origin=null,this.coordinates={x:-1,y:-1}},a.CursorCoordinatesController.prototype.init=function(){this.coordinatesContainer=document.querySelector(".cursor-coordinates"),$.subscribe(Events.CURSOR_MOVED,this.onCursorMoved_.bind(this)),$.subscribe(Events.DRAG_START,this.onDragStart_.bind(this)),$.subscribe(Events.DRAG_END,this.onDragEnd_.bind(this)),$.subscribe(Events.FRAME_SIZE_CHANGED,this.redraw.bind(this)),this.redraw()},a.CursorCoordinatesController.prototype.redraw=function(){var a="";this.origin&&(a+=this.origin.x+":"+this.origin.y+" to ");var b=this.coordinates.x,c=this.coordinates.y,d=this.piskelController.getCurrentFrame();if(d.containsPixel(b,c)&&(a+=b+":"+c,this.origin)){var e=Math.abs(b-this.origin.x)+1,f=Math.abs(c-this.origin.y)+1;a+=" ("+e+"x"+f+")"}this.coordinatesContainer.innerHTML=this.getFrameSizeHTML_()+a},a.CursorCoordinatesController.prototype.getFrameSizeHTML_=function(){var a=this.piskelController.getWidth(),b=this.piskelController.getHeight();return"["+a+"x"+b+"] "},a.CursorCoordinatesController.prototype.onCursorMoved_=function(a,b,c){this.coordinates={x:b,y:c},this.redraw()},a.CursorCoordinatesController.prototype.onDragStart_=function(a,b,c){this.origin={x:b,y:c},this.redraw()},a.CursorCoordinatesController.prototype.onDragEnd_=function(){this.origin=null,this.redraw()}}(),function(){var a=$.namespace("pskl.controller");a.DrawingController=function(a,b,c){this.piskelController=a,this.paletteController=b,this.overlayFrame=pskl.model.Frame.createEmptyFromFrame(a.getCurrentFrame()),this.container=c;var d={zoom:this.calculateZoom_(),supportGridRendering:!0,height:this.getContainerHeight_(),width:this.getContainerWidth_(),xOffset:0,yOffset:0};this.overlayRenderer=new pskl.rendering.frame.CachedFrameRenderer(this.container,d,["canvas-overlay"]),this.renderer=new pskl.rendering.frame.CachedFrameRenderer(this.container,d,["drawing-canvas"]),this.onionSkinRenderer=new pskl.rendering.OnionSkinRenderer(this.container,d,a),this.layersRenderer=new pskl.rendering.layer.LayersRenderer(this.container,d,a),this.compositeRenderer=new pskl.rendering.CompositeRenderer,this.compositeRenderer.add(this.overlayRenderer).add(this.renderer).add(this.layersRenderer).add(this.onionSkinRenderer),this.isClicked=!1,this.previousMousemoveTime=0,this.currentToolBehavior=null,this.currentMouseButton_=Constants.LEFT_BUTTON},a.DrawingController.prototype.init=function(){this.initMouseBehavior(),$.subscribe(Events.TOOL_SELECTED,$.proxy(function(a,b){this.currentToolBehavior=b,this.overlayFrame.clear()},this)),$(window).resize($.proxy(this.startResizeTimer_,this)),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this)),$.subscribe(Events.FRAME_SIZE_CHANGED,$.proxy(this.onFrameSizeChanged_,this)),pskl.app.shortcutService.addShortcut("0",this.resetZoom_.bind(this)),pskl.app.shortcutService.addShortcut("+",this.increaseZoom_.bind(this,1)),pskl.app.shortcutService.addShortcut("-",this.decreaseZoom_.bind(this,1)),window.setTimeout(this.afterWindowResize_.bind(this),100)},a.DrawingController.prototype.initMouseBehavior=function(){var a=$("body");this.container.mousedown($.proxy(this.onMousedown_,this)),pskl.utils.UserAgent.isChrome?this.container.on("mousewheel",$.proxy(this.onMousewheel_,this)):this.container.on("wheel",$.proxy(this.onMousewheel_,this)),window.addEventListener("mouseup",this.onMouseup_.bind(this)),window.addEventListener("mousemove",this.onMousemove_.bind(this)),window.addEventListener("keyup",this.onKeyup_.bind(this)),a.contextmenu(this.onCanvasContextMenu_)},a.DrawingController.prototype.startResizeTimer_=function(){this.resizeTimer&&window.clearInterval(this.resizeTimer),this.resizeTimer=window.setTimeout($.proxy(this.afterWindowResize_,this),200)},a.DrawingController.prototype.afterWindowResize_=function(){var a=this.compositeRenderer.getDisplaySize().width;this.compositeRenderer.setDisplaySize(this.getContainerWidth_(),this.getContainerHeight_()),this.centerColumnWrapperHorizontally_();var b=this.compositeRenderer.getDisplaySize().width/a,c=b*this.compositeRenderer.getZoom();this.compositeRenderer.setZoom(c),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.SHOW_GRID?console.warn("DrawingController:onUserSettingsChange_ not implemented !"):(b==pskl.UserSettings.ONION_SKIN||b==pskl.UserSettings.LAYER_PREVIEW)&&(this.onionSkinRenderer.clear(),this.onionSkinRenderer.flush(),this.layersRenderer.clear(),this.layersRenderer.flush(),this.render())},a.DrawingController.prototype.onFrameSizeChanged_=function(){this.compositeRenderer.setDisplaySize(this.getContainerWidth_(),this.getContainerHeight_()),this.centerColumnWrapperHorizontally_(),this.compositeRenderer.setZoom(this.calculateZoom_()),this.compositeRenderer.setOffset(0,0),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onMousedown_=function(a){$.publish(Events.MOUSE_EVENT,[a,this]);var b=this.piskelController.getCurrentFrame(),c=this.getSpriteCoordinates(a.clientX,a.clientY);a.button===Constants.MIDDLE_BUTTON?b.containsPixel(c.x,c.y)&&$.publish(Events.SELECT_PRIMARY_COLOR,[b.getPixel(c.x,c.y)]):(this.isClicked=!0,this.setCurrentButton(a),this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame),this.currentToolBehavior.applyToolAt(c.x,c.y,this.getCurrentColor_(),b,this.overlayFrame,a))},a.DrawingController.prototype.onMousemove_=function(a){this._clientX=a.clientX,this._clientY=a.clientY;var b=(new Date).getTime();b-this.previousMousemoveTime>Constants.MOUSEMOVE_THROTTLING&&(this.moveTool_(this._clientX,this._clientY,a),this.previousMousemoveTime=b)},a.DrawingController.prototype.resetZoom_=function(){this.setZoom_(this.calculateZoom_())},a.DrawingController.prototype.increaseZoom_=function(a){var b=(a||1)*this.getZoomStep_();this.setZoom_(this.renderer.getZoom()+b)},a.DrawingController.prototype.decreaseZoom_=function(a){var b=(a||1)*this.getZoomStep_();this.setZoom_(this.renderer.getZoom()-b)},a.DrawingController.prototype.getZoomStep_=function(){return this.calculateZoom_()/10},a.DrawingController.prototype.setZoom_=function(a){this.compositeRenderer.setZoom(a),$.publish(Events.ZOOM_CHANGED)},a.DrawingController.prototype.onKeyup_=function(a){this.moveTool_(this._clientX,this._clientY,a)},a.DrawingController.prototype.moveTool_=function(a,b,c){var d=this.getSpriteCoordinates(a,b),e=this.piskelController.getCurrentFrame();this.isClicked?($.publish(Events.MOUSE_EVENT,[c,this]),this.currentToolBehavior.moveToolAt(0|d.x,0|d.y,this.getCurrentColor_(),e,this.overlayFrame,c)):this.currentToolBehavior.moveUnactiveToolAt(d.x,d.y,this.getCurrentColor_(),e,this.overlayFrame,c),$.publish(Events.CURSOR_MOVED,[d.x,d.y])},a.DrawingController.prototype.onMousewheel_=function(a){var b=a.originalEvent,c=b.wheelDeltaY||-2*b.deltaY,d=Math.abs(c/120);c>0?this.increaseZoom_(d):0>c&&this.decreaseZoom_(d)},a.DrawingController.prototype.onMouseup_=function(a){if(this.isClicked){$.publish(Events.MOUSE_EVENT,[a,this]),this.isClicked=!1,this.setCurrentButton(a);var b=this.getSpriteCoordinates(a.clientX,a.clientY);this.currentToolBehavior.releaseToolAt(b.x,b.y,this.getCurrentColor_(),this.piskelController.getCurrentFrame(),this.overlayFrame,a),$.publish(Events.TOOL_RELEASED)}},a.DrawingController.prototype.getSpriteCoordinates=function(a,b){return this.renderer.getCoordinates(a,b)},a.DrawingController.prototype.getScreenCoordinates=function(a,b){return this.renderer.reverseCoordinates(a,b)},a.DrawingController.prototype.setCurrentButton=function(a){this.currentMouseButton_=a.button},a.DrawingController.prototype.getCurrentColor_=function(){return this.currentMouseButton_==Constants.RIGHT_BUTTON?this.paletteController.getSecondaryColor():this.currentMouseButton_==Constants.LEFT_BUTTON?this.paletteController.getPrimaryColor():Constants.DEFAULT_PEN_COLOR},a.DrawingController.prototype.onCanvasContextMenu_=function(a){return $(a.target).closest("#drawing-canvas-container").length?(a.preventDefault(),a.stopPropagation(),a.cancelBubble=!0,!1):void 0},a.DrawingController.prototype.render=function(){var a=this.piskelController.getCurrentFrame();a.isSameSize(this.overlayFrame)||(this.overlayFrame=pskl.model.Frame.createEmptyFromFrame(a)),pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)&&this.onionSkinRenderer.render(),pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)&&this.layersRenderer.render(),this.renderer.render(a),this.overlayRenderer.render(this.overlayFrame)},a.DrawingController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame().getHeight(),b=this.piskelController.getCurrentFrame().getWidth();return Math.min(this.getAvailableWidth_()/b,this.getAvailableHeight_()/a)},a.DrawingController.prototype.getAvailableHeight_=function(){return $("#main-wrapper").height()},a.DrawingController.prototype.getAvailableWidth_=function(){var a=$(".left-column").outerWidth(!0),b=$(".right-column").outerWidth(!0),c=$("#tool-section").outerWidth(!0),d=$("#application-action-section").outerWidth(!0),e=$("#main-wrapper").width()-a-b-c-d,f=10; -return e-f},a.DrawingController.prototype.getContainerHeight_=function(){return this.calculateZoom_()*this.piskelController.getCurrentFrame().getHeight()},a.DrawingController.prototype.getContainerWidth_=function(){return this.calculateZoom_()*this.piskelController.getCurrentFrame().getWidth()},a.DrawingController.prototype.centerColumnWrapperHorizontally_=function(){var a=this.getContainerHeight_(),b=Math.floor(($("#main-wrapper").height()-a)/2);$("#column-wrapper").css({top:b+"px"})},a.DrawingController.prototype.getRenderer=function(){return this.compositeRenderer},a.DrawingController.prototype.setOffset=function(a,b){this.compositeRenderer.setOffset(a,b),$.publish(Events.ZOOM_CHANGED)}}(),function(){var a=$.namespace("pskl.controller"),b={SELECT:"select",CLONE:"clone",DELETE:"delete",NEW_FRAME:"newframe"};a.PreviewFilmController=function(a,b){this.piskelController=a,this.container=b,this.refreshZoom_(),this.redrawFlag=!0,this.cachedFrameProcessor=new pskl.model.frame.CachedFrameProcessor,this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)),this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this))},a.PreviewFilmController.prototype.init=function(){$.subscribe(Events.TOOL_RELEASED,this.flagForRedraw_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.flagForRedraw_.bind(this)),$.subscribe(Events.USER_SETTINGS_CHANGED,this.flagForRedraw_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.refreshZoom_.bind(this)),$("#preview-list-scroller").scroll(this.updateScrollerOverflows.bind(this)),this.container.get(0).addEventListener("click",this.onContainerClick_.bind(this)),this.updateScrollerOverflows()},a.PreviewFilmController.prototype.flagForRedraw_=function(){this.redrawFlag=!0},a.PreviewFilmController.prototype.refreshZoom_=function(){this.zoom=this.calculateZoom_()},a.PreviewFilmController.prototype.render=function(){this.redrawFlag&&(this.createPreviews_(),this.redrawFlag=!1)},a.PreviewFilmController.prototype.updateScrollerOverflows=function(){var a=$("#preview-list-scroller"),b=a.height(),c=a.scrollTop(),d=$("#preview-list").height(),e=$(".top-overflow").height(),f=!1,g=!1;if(d>b){c>e&&(f=!0);var h=d-c-b;h>e&&(g=!0)}var i=$("#preview-list-wrapper");i.toggleClass("top-overflow-visible",f),i.toggleClass("bottom-overflow-visible",g)},a.PreviewFilmController.prototype.onContainerClick_=function(a){var c=pskl.utils.Dom.getParentWithData(a.target,"tileAction");if(c){var d=c.dataset.tileAction,e=parseInt(c.dataset.tileNumber,10);d===b.CLONE?(this.piskelController.duplicateFrameAt(e),this.updateScrollerOverflows()):d===b.DELETE?(this.piskelController.removeFrameAt(e),this.updateScrollerOverflows()):d===b.SELECT?this.piskelController.setCurrentFrameIndex(e):d===b.NEW_FRAME&&(this.piskelController.addFrame(),this.updateScrollerOverflows())}},a.PreviewFilmController.prototype.createPreviews_=function(){this.container.html(""),$(".tooltip").remove();for(var a=this.piskelController.getFrameCount(),c=0,d=a;d>c;c++)this.container.append(this.createPreviewTile_(c));var e=document.createElement("div");e.id="add-frame-action",e.className="add-frame-action",e.setAttribute("data-tile-action",b.NEW_FRAME),e.innerHTML="

        Add new frame

        ",this.container.append(e);var f=a>1;f&&this.initDragndropBehavior_(),this.updateScrollerOverflows()},a.PreviewFilmController.prototype.initDragndropBehavior_=function(){$("#preview-list").sortable({placeholder:"preview-tile-drop-proxy",update:$.proxy(this.onUpdate_,this),items:".preview-tile"}),$("#preview-list").disableSelection()},a.PreviewFilmController.prototype.onUpdate_=function(a,b){var c=parseInt(b.item.data("tile-number"),10),d=$(".preview-tile").index(b.item);this.piskelController.moveFrame(c,d),this.piskelController.setCurrentFrameIndex(d)},a.PreviewFilmController.prototype.createPreviewTile_=function(a){var c=this.piskelController.getCurrentLayer().getFrameAt(a),d=document.createElement("li");d.setAttribute("data-tile-number",a),d.setAttribute("data-tile-action",b.SELECT),d.classList.add("preview-tile"),this.piskelController.getCurrentFrame()==c&&d.classList.add("selected");var e=document.createElement("div");e.classList.add("canvas-container",pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND));var f=document.createElement("div");f.className="canvas-background",e.appendChild(f);var g=document.createElement("button");if(g.setAttribute("rel","tooltip"),g.setAttribute("data-placement","right"),g.setAttribute("data-tile-number",a),g.setAttribute("data-tile-action",b.CLONE),g.setAttribute("title","Duplicate this frame"),g.className="tile-overlay duplicate-frame-action",d.appendChild(g),e.appendChild(this.getCanvasForFrame(c)),d.appendChild(e),a>0||this.piskelController.getFrameCount()>1){var h=document.createElement("button");h.setAttribute("rel","tooltip"),h.setAttribute("data-placement","right"),h.setAttribute("title","Delete this frame"),h.setAttribute("data-tile-number",a),h.setAttribute("data-tile-action",b.DELETE),h.className="tile-overlay delete-frame-action",d.appendChild(h);var i=document.createElement("div");i.className="tile-overlay dnd-action",d.appendChild(i)}var j=document.createElement("div");return j.className="tile-overlay tile-count",j.innerHTML=a+1,d.appendChild(j),d},a.PreviewFilmController.prototype.getCanvasForFrame=function(a){var b=this.cachedFrameProcessor.get(a,this.zoom);return b},a.PreviewFilmController.prototype.frameToPreviewCanvas_=function(a){var b=new pskl.rendering.CanvasRenderer(a,this.zoom);b.drawTransparentAs(Constants.TRANSPARENT_COLOR);var c=b.render();return c.classList.add("tile-view","canvas"),c},a.PreviewFilmController.prototype.clonePreviewCanvas_=function(a){var b=pskl.CanvasUtils.clone(a);return b.classList.add("tile-view","canvas"),b},a.PreviewFilmController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame(),b=a.getHeight(),c=a.getWidth();return Math.min(Constants.PREVIEW_FILM_SIZE/b,Constants.PREVIEW_FILM_SIZE/c)}}(),function(){var a=$.namespace("pskl.controller");a.LayersListController=function(a){this.piskelController=a},a.LayersListController.prototype.init=function(){this.layerItemTemplate_=pskl.utils.Template.get("layer-item-template"),this.rootEl=document.querySelector(".layers-list-container"),this.layersListEl=document.querySelector(".layers-list"),this.toggleLayerPreviewEl=document.querySelector(".layers-toggle-preview"),this.rootEl.addEventListener("click",this.onClick_.bind(this)),this.toggleLayerPreviewEl.addEventListener("click",this.toggleLayerPreview_.bind(this)),$.subscribe(Events.PISKEL_RESET,this.renderLayerList_.bind(this)),pskl.app.shortcutService.addShortcut("alt+L",this.toggleLayerPreview_.bind(this)),this.renderLayerList_(),this.updateToggleLayerPreview_(),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this))},a.LayersListController.prototype.renderLayerList_=function(){this.layersListEl.innerHTML="";var a=this.piskelController.getLayers();a.forEach(this.addLayerItem.bind(this))},a.LayersListController.prototype.updateToggleLayerPreview_=function(){var a="layers-toggle-preview-enabled";pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW)?this.toggleLayerPreviewEl.classList.add(a):this.toggleLayerPreviewEl.classList.remove(a)},a.LayersListController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.LAYER_PREVIEW&&this.updateToggleLayerPreview_()},a.LayersListController.prototype.addLayerItem=function(a,b){var c=this.piskelController.getCurrentLayer()===a,d=pskl.utils.Template.replace(this.layerItemTemplate_,{layername:a.getName(),layerindex:b,"isselected:current-layer-item":c}),e=pskl.utils.Template.createFromHTML(d);this.layersListEl.insertBefore(e,this.layersListEl.firstChild)},a.LayersListController.prototype.onClick_=function(a){var b,c=a.target||a.srcElement;c.classList.contains("button")?this.onButtonClick_(c):c.classList.contains("layer-item")?(b=c.dataset.layerIndex,this.piskelController.setCurrentLayerIndex(parseInt(b,10))):c.classList.contains("edit-icon")&&(b=c.parentNode.dataset.layerIndex,this.renameLayerAt_(b))},a.LayersListController.prototype.renameLayerAt_=function(a){var b=this.piskelController.getLayerAt(a),c=window.prompt("Please enter the layer name",b.getName());c&&(this.piskelController.renameLayerAt(a,c),this.renderLayerList_())},a.LayersListController.prototype.onButtonClick_=function(a){var b=a.getAttribute("data-action");"up"==b?this.piskelController.moveLayerUp():"down"==b?this.piskelController.moveLayerDown():"add"==b?this.piskelController.createLayer():"delete"==b&&this.piskelController.removeCurrentLayer()},a.LayersListController.prototype.toggleLayerPreview_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.LAYER_PREVIEW);pskl.UserSettings.set(pskl.UserSettings.LAYER_PREVIEW,!a)}}(),function(){var a=$.namespace("pskl.controller"),b=200;a.AnimatedPreviewController=function(a,b){this.piskelController=a,this.container=b,this.elapsedTime=0,this.currentIndex=0,this.setFPS(Constants.DEFAULT.FPS);this.piskelController.getCurrentFrame();this.renderer=new pskl.rendering.frame.TiledFrameRenderer(this.container)},a.AnimatedPreviewController.prototype.init=function(){$("#preview-fps")[0].addEventListener("change",this.onFPSSliderChange.bind(this)),document.querySelector(".right-column").style.width=Constants.ANIMATED_PREVIEW_WIDTH+"px",this.toggleOnionSkinEl=document.querySelector(".preview-toggle-onion-skin"),this.toggleOnionSkinEl.addEventListener("click",this.toggleOnionSkin_.bind(this)),pskl.app.shortcutService.addShortcut("alt+O",this.toggleOnionSkin_.bind(this)),$.subscribe(Events.FRAME_SIZE_CHANGED,this.onFrameSizeChange_.bind(this)),$.subscribe(Events.USER_SETTINGS_CHANGED,$.proxy(this.onUserSettingsChange_,this)),this.updateZoom_(),this.updateOnionSkinPreview_()},a.AnimatedPreviewController.prototype.onUserSettingsChange_=function(a,b){b==pskl.UserSettings.ONION_SKIN?this.updateOnionSkinPreview_():(this.updateZoom_(),this.updateContainerDimensions_())},a.AnimatedPreviewController.prototype.updateOnionSkinPreview_=function(){var a="preview-toggle-onion-skin-enabled";pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)?this.toggleOnionSkinEl.classList.add(a):this.toggleOnionSkinEl.classList.remove(a)},a.AnimatedPreviewController.prototype.updateZoom_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW),b=a?1:this.calculateZoom_();this.renderer.setZoom(b)},a.AnimatedPreviewController.prototype.getZoom=function(){return this.calculateZoom_()},a.AnimatedPreviewController.prototype.getCoordinates=function(a,b){var c=this.container.offset();a-=c.left,b-=c.top;var d=this.getZoom();return{x:Math.floor(a/d),y:Math.floor(b/d)}},a.AnimatedPreviewController.prototype.onFPSSliderChange=function(){this.setFPS(parseInt($("#preview-fps")[0].value,10))},a.AnimatedPreviewController.prototype.setFPS=function(a){a&&(this.fps=a,$("#preview-fps").val(this.fps),$("#display-fps").html(this.fps+" FPS"))},a.AnimatedPreviewController.prototype.getFPS=function(){return this.fps},a.AnimatedPreviewController.prototype.render=function(a){this.elapsedTime+=a;var b=Math.floor(this.elapsedTime/(1e3/this.fps));if(b!=this.currentIndex){this.currentIndex=b,this.piskelController.hasFrameAt(this.currentIndex)||(this.currentIndex=0,this.elapsedTime=0);var c=this.piskelController.getFrameAt(this.currentIndex);this.renderer.render(c)}},a.AnimatedPreviewController.prototype.calculateZoom_=function(){var a=this.piskelController.getCurrentFrame(),b=200,c=b/a.getHeight(),d=b/a.getWidth();return Math.min(c,d)},a.AnimatedPreviewController.prototype.onFrameSizeChange_=function(){this.updateZoom_(),this.updateContainerDimensions_()},a.AnimatedPreviewController.prototype.updateContainerDimensions_=function(){var a,c,d=this.container.get(0),e=pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW);if(e)a=b,c=b;else{var f=this.getZoom(),g=this.piskelController.getCurrentFrame();a=g.getHeight()*f,c=g.getWidth()*f}d.style.height=a+"px",d.style.width=c+"px",d.style.marginTop=(b-a)/2+"px",d.style.marginBottom=(b-a)/2+"px",d.style.marginLeft=(b-c)/2+"px",d.style.marginRight=(b-c)/2+"px"},a.AnimatedPreviewController.prototype.toggleOnionSkin_=function(){var a=pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN);pskl.UserSettings.set(pskl.UserSettings.ONION_SKIN,!a)}}(),function(){var a=$.namespace("pskl.controller");a.MinimapController=function(a,b,c,d){this.piskelController=a,this.animationController=b,this.drawingController=c,this.container=d,this.isClicked=!1},a.MinimapController.prototype.init=function(){this.cropFrame=document.createElement("DIV"),this.cropFrame.className="minimap-crop-frame",this.cropFrame.style.display="none",$(this.container).append(this.cropFrame),$(this.container).mousedown(this.onMinimapMousedown_.bind(this)),$("body").mousemove(this.onMinimapMousemove_.bind(this)),$("body").mouseup(this.onMinimapMouseup_.bind(this)),$.subscribe(Events.ZOOM_CHANGED,$.proxy(this.renderMinimap_,this))},a.MinimapController.prototype.renderMinimap_=function(){var a=this.getDrawingAreaZoomRatio_();a>1?this.displayCropFrame_(a,this.drawingController.getRenderer().getOffset()):this.hideCropFrame_()},a.MinimapController.prototype.displayCropFrame_=function(a,b){this.cropFrame.style.display="block",this.cropFrame.style.top=b.y*this.animationController.getZoom()+"px",this.cropFrame.style.left=b.x*this.animationController.getZoom()+"px";var c=this.getDrawingAreaZoomRatio_();this.cropFrame.style.width=this.container.width()/c+"px",this.cropFrame.style.height=this.container.height()/c+"px"},a.MinimapController.prototype.hideCropFrame_=function(){this.cropFrame.style.display="none"},a.MinimapController.prototype.onMinimapMousemove_=function(a){if(this.isClicked&&this.getDrawingAreaZoomRatio_()>1){var b=this.getCoordinatesCenteredAround_(a.clientX,a.clientY);this.drawingController.setOffset(b.x,b.y)}},a.MinimapController.prototype.onMinimapMousedown_=function(){this.isClicked=!0},a.MinimapController.prototype.onMinimapMouseup_=function(){this.isClicked=!1},a.MinimapController.prototype.getCoordinatesCenteredAround_=function(a,b){var c=this.animationController.getCoordinates(a,b),d=this.getDrawingAreaZoomRatio_(),e=this.piskelController.getCurrentFrame().getWidth(),f=this.piskelController.getCurrentFrame().getHeight(),g=e/d,h=f/d;return{x:c.x-g/2,y:c.y-h/2}},a.MinimapController.prototype.getDrawingAreaZoomRatio_=function(){var a=this.drawingController.getRenderer().getZoom(),b=this.piskelController.getCurrentFrame().getHeight()*a,c=b/this.drawingController.getRenderer().getDisplaySize().height;return c}}(),function(){var a=$.namespace("pskl.controller");a.ToolController=function(){var a=function(a,b,c){return{id:a,shortcut:b,instance:c}};this.tools=[a("simplePen","P",new pskl.drawingtools.SimplePen),a("verticalMirrorPen","V",new pskl.drawingtools.VerticalMirrorPen),a("paintBucket","B",new pskl.drawingtools.PaintBucket),a("colorSwap","A",new pskl.drawingtools.ColorSwap),a("eraser","E",new pskl.drawingtools.Eraser),a("stroke","L",new pskl.drawingtools.Stroke),a("rectangle","R",new pskl.drawingtools.Rectangle),a("circle","C",new pskl.drawingtools.Circle),a("move","M",new pskl.drawingtools.Move),a("rectangleSelect","S",new pskl.drawingtools.RectangleSelect),a("shapeSelect","Z",new pskl.drawingtools.ShapeSelect),a("lighten","U",new pskl.drawingtools.Lighten),a("colorPicker","O",new pskl.drawingtools.ColorPicker)],this.currentSelectedTool=this.tools[0],this.previousSelectedTool=this.tools[0]},a.ToolController.prototype.init=function(){this.createToolsDom_(),this.addKeyboardShortcuts_(),this.selectTool_(this.tools[0]),$("#tool-section").mousedown($.proxy(this.onToolIconClicked_,this)),$.subscribe(Events.SELECT_TOOL,this.onSelectToolEvent_.bind(this))},a.ToolController.prototype.activateToolOnStage_=function(a){var b=$("body"),c=b.data("selected-tool-class");c&&(b.removeClass(c),b.removeClass(pskl.drawingtools.Move.TOOL_ID)),b.addClass(a.instance.toolId),b.data("selected-tool-class",a.instance.toolId)},a.ToolController.prototype.onSelectToolEvent_=function(a,b){var c=this.getToolById_(b);c&&this.selectTool_(c)},a.ToolController.prototype.selectTool_=function(a){this.currentSelectedTool=a,this.activateToolOnStage_(this.currentSelectedTool);var b=$("#tool-section .tool-icon.selected"),c=$("[data-tool-id="+a.instance.toolId+"]");b.removeClass("selected"),c.addClass("selected"),$.publish(Events.TOOL_SELECTED,[a.instance])},a.ToolController.prototype.onToolIconClicked_=function(a){var b=$(a.target),c=b.closest(".tool-icon");if(c.length){var d=c.data().toolId,e=this.getToolById_(d);e&&this.selectTool_(e)}},a.ToolController.prototype.onKeyboardShortcut_=function(a){for(var b=0;b{{name}}',a)}).join("");this.colorPaletteSelect_.innerHTML=b},a.PalettesListController.prototype.fillColorListContainer=function(){var a=this.getSelectedPaletteColors_(),b=a.map(function(a){return pskl.utils.Template.replace(this.paletteColorTemplate_,{color:a})}.bind(this)).join("");this.colorListContainer_.innerHTML=b,this.highlightSelectedColors();var c=a.length>e;c&&!pskl.utils.UserAgent.isChrome?this.colorListContainer_.classList.add(d):this.colorListContainer_.classList.remove(d)},a.PalettesListController.prototype.getSelectedPaletteColors_=function(){var a=[],b=this.colorPaletteSelect_.value;if(b===Constants.CURRENT_COLORS_PALETTE_ID)a=this.usedColorService.getCurrentColors();else{var c=this.paletteService.getPaletteById(b);c&&(a=c.colors)}return a.length>Constants.MAX_CURRENT_COLORS_DISPLAYED&&(a=a.slice(0,Constants.MAX_CURRENT_COLORS_DISPLAYED)),a},a.PalettesListController.prototype.selectPaletteFromUserSettings=function(){this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE))},a.PalettesListController.prototype.selectPalette=function(a){this.colorPaletteSelect_.value=a},a.PalettesListController.prototype.onPaletteSelected_=function(){var a=this.colorPaletteSelect_.value;pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE,a),this.fillColorListContainer()},a.PalettesListController.prototype.onCreatePaletteClick_=function(){$.publish(Events.DIALOG_DISPLAY,"create-palette")},a.PalettesListController.prototype.onPaletteActionsClick_=function(a){var b=a.target.classList;b.contains("palette-action-edit")?this.editSelectedPalette_():b.contains("palette-action-delete")?this.deleteSelectedPalette_():b.contains("palette-action-download")&&this.downloadSelectedPalette_()},a.PalettesListController.prototype.editSelectedPalette_=function(){var a=this.colorPaletteSelect_.value;$.publish(Events.DIALOG_DISPLAY,{dialogId:"create-palette",initArgs:a})},a.PalettesListController.prototype.deleteSelectedPalette_=function(){var a=this.colorPaletteSelect_.value,b=this.paletteService.getPaletteById(a);window.confirm("Are you sure you want to delete palette "+b.name)&&(this.paletteService.deletePaletteById(b.id),this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID))},a.PalettesListController.prototype.downloadSelectedPalette_=function(){window.alert("not implemented yet")},a.PalettesListController.prototype.onColorContainerContextMenu=function(a){a.preventDefault()},a.PalettesListController.prototype.onColorContainerMouseup=function(a){var b=a.target,c=b.dataset.color;c&&(a.button==Constants.LEFT_BUTTON?$.publish(Events.SELECT_PRIMARY_COLOR,[c]):a.button==Constants.RIGHT_BUTTON&&$.publish(Events.SELECT_SECONDARY_COLOR,[c]))},a.PalettesListController.prototype.highlightSelectedColors=function(){this.removeClass_(b),this.removeClass_(c);var a=this.getColorContainer_(this.paletteController.getSecondaryColor());a&&(a.classList.remove(b),a.classList.add(c)),a=this.getColorContainer_(this.paletteController.getPrimaryColor()),a&&(a.classList.remove(c),a.classList.add(b))},a.PalettesListController.prototype.getColorContainer_=function(a){return this.colorListContainer_.querySelector('.palettes-list-color[data-color="'+a+'"]')},a.PalettesListController.prototype.removeClass_=function(a){var b=document.querySelector("."+a);b&&b.classList.remove(a)},a.PalettesListController.prototype.onPaletteListUpdated=function(){this.fillPaletteList(),this.selectPaletteFromUserSettings(),this.fillColorListContainer()}}(),function(){var a=$.namespace("pskl.controller");a.NotificationController=function(){},a.NotificationController.prototype.init=function(){$.subscribe(Events.SHOW_NOTIFICATION,$.proxy(this.displayMessage_,this)),$.subscribe(Events.HIDE_NOTIFICATION,$.proxy(this.removeMessage_,this))},a.NotificationController.prototype.displayMessage_=function(a,b){this.removeMessage_();var c=document.createElement("div");c.id="user-message",c.className="user-message",c.innerHTML=b.content,c.innerHTML=c.innerHTML+"
        x
        ",document.body.appendChild(c),$(c).find(".close").click($.proxy(this.removeMessage_,this)),b.behavior&&b.behavior(c)},a.NotificationController.prototype.removeMessage_=function(){var a=$("#user-message");a.length&&a.remove()}}(),function(){var a=$.namespace("pskl.controller");a.CanvasBackgroundController=function(){this.body=document.body},a.CanvasBackgroundController.prototype.init=function(){$.subscribe(Events.USER_SETTINGS_CHANGED,this.onUserSettingsChange_.bind(this)),this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND))},a.CanvasBackgroundController.prototype.onUserSettingsChange_=function(a,b,c){b==pskl.UserSettings.CANVAS_BACKGROUND&&this.updateBackgroundClass_(c)},a.CanvasBackgroundController.prototype.updateBackgroundClass_=function(a){var b=this.body.dataset.currentBackgroundClass;b&&this.body.classList.remove(b),this.body.classList.add(a),this.body.dataset.currentBackgroundClass=a}}(),function(){var a=$.namespace("pskl.controller.settings");a.ApplicationSettingsController=function(){},a.ApplicationSettingsController.prototype.init=function(){var a=pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND);$("#background-picker-wrapper").find(".background-picker[data-background-class="+a+"]").addClass("selected");var b=pskl.UserSettings.get(pskl.UserSettings.GRID_WIDTH);$("#grid-width").val(b),$("#grid-width").change(this.onGridWidthChange.bind(this)),$("#background-picker-wrapper").click(this.onBackgroundClick.bind(this))},a.ApplicationSettingsController.prototype.onGridWidthChange=function(){var a=$("#grid-width").val();pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH,parseInt(a,10))},a.ApplicationSettingsController.prototype.onBackgroundClick=function(a){var b=$(a.target).closest(".background-picker");if(b.length){var c=b.data("background-class");pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND,c),$(".background-picker").removeClass("selected"),b.addClass("selected")}}}(),function(){var a=$.namespace("pskl.controller.settings");a.ResizeController=function(a){this.piskelController=a},a.ResizeController.prototype.init=function(){this.resizeWidth=$("[name=resize-width]"),this.resizeHeight=$("[name=resize-height]"),this.resizeWidth.val(this.piskelController.getWidth()),this.resizeHeight.val(this.piskelController.getHeight()),this.cancelButton=$(".resize-cancel-button"),this.cancelButton.click(this.onCancelButtonClicked_.bind(this)),this.resizeForm=$("[name=resize-form]"),this.resizeForm.submit(this.onResizeFormSubmit_.bind(this)),this.resizeContentCheckbox=$(".resize-content-checkbox")},a.ResizeController.prototype.onResizeFormSubmit_=function(a){a.originalEvent.preventDefault();var b=(parseInt(this.resizeWidth.val(),10),parseInt(this.resizeHeight.val(),10),this.isResizeContentEnabled_(),this.piskelController.getLayers().map(this.resizeLayer_.bind(this))),c=pskl.model.Piskel.fromLayers(b,this.piskelController.getPiskel().getDescriptor());pskl.app.piskelController.setPiskel(c,!0),$.publish(Events.CLOSE_SETTINGS_DRAWER)},a.ResizeController.prototype.resizeLayer_=function(a){var b=a.getFrames().map(this.resizeFrame_.bind(this));return pskl.model.Layer.fromFrames(a.getName(),b)},a.ResizeController.prototype.resizeFrame_=function(a){var b,c=parseInt(this.resizeWidth.val(),10),d=parseInt(this.resizeHeight.val(),10);return this.isResizeContentEnabled_()?b=pskl.utils.FrameUtils.resize(a,c,d,!1):(b=new pskl.model.Frame(c,d),a.forEachPixel(function(a,c,d){c=f;f++)a.GifExportController.RESOLUTIONS.push({zoom:f});a.GifExportController.prototype.init=function(){this.optionTemplate_=pskl.utils.Template.get("gif-export-option-template"),this.uploadStatusContainerEl=document.querySelector(".gif-upload-status"),this.previewContainerEl=document.querySelector(".gif-export-preview"),this.selectResolutionEl=document.querySelector(".gif-export-select-resolution"),this.uploadButton=$(".gif-upload-button"),this.uploadButton.click(this.onUploadButtonClick_.bind(this)),this.downloadButton=$(".gif-download-button"),this.downloadButton.click(this.onDownloadButtonClick_.bind(this)),this.exportProgressStatusEl=document.querySelector(".gif-export-progress-status"),this.exportProgressBarEl=document.querySelector(".gif-export-progress-bar"),this.createOptionElements_()},a.GifExportController.prototype.onUploadButtonClick_=function(a){a.originalEvent.preventDefault();var b=this.getSelectedZoom_(),c=this.piskelController.getFPS();this.renderAsImageDataAnimatedGIF(b,c,this.onGifRenderingCompleted_.bind(this))},a.GifExportController.prototype.onDownloadButtonClick_=function(){var a=this.piskelController.getPiskel().getDescriptor().name+".gif",b=this.getSelectedZoom_(),c=this.piskelController.getFPS();this.renderAsImageDataAnimatedGIF(b,c,function(b){pskl.utils.BlobUtils.dataToBlob(b,"image/gif",function(b){pskl.utils.FileUtils.downloadAsFile(b,a)})}.bind(this))},a.GifExportController.prototype.onGifRenderingCompleted_=function(a){this.updatePreview_(a),this.previewContainerEl.classList.add("preview-upload-ongoing"),pskl.app.imageUploadService.upload(a,this.onImageUploadCompleted_.bind(this))},a.GifExportController.prototype.onImageUploadCompleted_=function(a){this.updatePreview_(a),this.updateStatus_(a),this.previewContainerEl.classList.remove("preview-upload-ongoing") -},a.GifExportController.prototype.updatePreview_=function(a){this.previewContainerEl.innerHTML="
        "},a.GifExportController.prototype.getSelectedZoom_=function(){return this.selectResolutionEl.value},a.GifExportController.prototype.createOptionElements_=function(){for(var b=a.GifExportController.RESOLUTIONS,c=0;ce,g=new window.GIF({workers:2,quality:1,width:this.piskelController.getWidth()*a,height:this.piskelController.getHeight()*a,preserveColors:f}),h=0;hb){var d=Math.round((b-c.length)/2),e=a.substring(0,d),f=a.substring(a.length-d,a.length);a=e+c+f}return a}}(),function(){var a=$.namespace("pskl.controller.settings"),b=60;a.PngExportController=function(a){this.piskelController=a},a.PngExportController.prototype.init=function(){this.previewContainerEl=document.querySelector(".png-export-preview"),this.pngFilePrefixInput=document.getElementById("zip-prefix-name"),this.pngFilePrefixInput.value="sprite_",document.querySelector(".png-download-button").addEventListener("click",this.onPngDownloadButtonClick_.bind(this)),document.querySelector(".zip-generate-button").addEventListener("click",this.onZipButtonClick_.bind(this)),this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png"))},a.PngExportController.prototype.onPngDownloadButtonClick_=function(){var a=this.getPiskelName_()+".png";pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(),function(b){pskl.utils.FileUtils.downloadAsFile(b,a)})},a.PngExportController.prototype.onZipButtonClick_=function(){for(var a=new window.JSZip,b=0;b"},a.PngExportController.prototype.shorten_=function(a,b,c){return a.length>b&&(a=a.substring(0,b),a+=c),a}}(),function(){var a=$.namespace("pskl.controller.settings");a.SaveController=function(a){this.piskelController=a},a.SaveController.prototype.init=function(){this.piskelName=document.querySelector(".piskel-name"),this.saveOnlineStatus=$("#save-online-status"),this.saveFileStatus=$("#save-file-status"),this.timestamp=new Date;var a=this.piskelController.getPiskel().getDescriptor();this.descriptionInput=$("#save-description"),this.descriptionInput.val(a.description),this.isPublicCheckbox=$("input[name=save-public-checkbox]"),this.isPublicCheckbox.prop("checked",a.isPublic),this.saveFileButton=$("#save-file-button"),this.saveFileButton.click(this.saveFile_.bind(this)),this.saveLocalButton=$("#save-browser-button"),this.saveLocalButton.click(this.saveLocal_.bind(this)),this.saveOnlineButton=$("#save-online-button"),this.saveOnlineButton.click(this.saveOnline_.bind(this)),this.saveForm=$("form[name=save-form]"),this.saveForm.submit(this.onSaveFormSubmit_.bind(this)),this.nameInput=$("#save-name"),this.nameInput.val(a.name),this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this)),pskl.app.isLoggedIn()?this.saveOnlineStatus.html(pskl.utils.Template.get("save-online-status-partial")):(this.saveOnlineButton.hide(),$(".save-public-section").hide(),this.saveOnlineStatus.html(pskl.utils.Template.get("save-please-login-partial"))),this.updateLocalStatusFilename_()},a.SaveController.prototype.updateLocalStatusFilename_=function(){this.saveFileStatus.html(pskl.utils.Template.getAndReplace("save-file-status-template",{name:this.getLocalFilename_()}))},a.SaveController.prototype.getLocalFilename_=function(){var a=this.getName(),b=pskl.utils.DateUtils.format(this.timestamp,"{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}");return a+"-"+b+".piskel"},a.SaveController.prototype.onSaveFormSubmit_=function(a){a.preventDefault(),a.stopPropagation(),pskl.app.isLoggedIn()?this.saveOnline_():this.saveLocal_()},a.SaveController.prototype.saveOnline_=function(){var a=this.getName();if(a||(a=window.prompt("Please specify a name","New piskel")),a){var b=this.getDescription(),c=!!this.isPublicCheckbox.prop("checked"),d=new pskl.model.piskel.Descriptor(a,b,c);this.piskelController.getPiskel().setDescriptor(d),this.beforeSaving_(),this.saveOnlineButton.attr("disabled",!0),this.saveOnlineStatus.html("Saving ..."),pskl.app.storageService.store({success:this.onSaveSuccess_.bind(this),error:this.onSaveError_.bind(this),after:this.afterOnlineSaving_.bind(this)})}},a.SaveController.prototype.saveLocal_=function(){var a=pskl.app.localStorageService,b=!0,c=this.getName(),d=this.getDescription();a.getPiskel(c)&&(b=window.confirm("There is already a piskel saved as "+c+". Override ?")),b&&(this.beforeSaving_(),a.save(c,d,pskl.app.piskelController.serialize()),window.setTimeout(function(){this.onSaveSuccess_(),this.afterSaving_()}.bind(this),500))},a.SaveController.prototype.saveFile_=function(){this.beforeSaving_(),pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(),function(a){pskl.utils.FileUtils.downloadAsFile(a,this.getLocalFilename_()),this.onSaveSuccess_(),this.afterSaving_()}.bind(this),"application/piskel+json")},a.SaveController.prototype.getName=function(){return this.nameInput.val()},a.SaveController.prototype.getDescription=function(){return this.descriptionInput.val()},a.SaveController.prototype.beforeSaving_=function(){this.updatePiskelDescriptor_(),this.piskelName&&this.piskelName.classList.add("piskel-name-saving")},a.SaveController.prototype.updatePiskelDescriptor_=function(){var a=this.getName(),b=this.getDescription(),c=!!this.isPublicCheckbox.prop("checked"),d=new pskl.model.piskel.Descriptor(a,b,c);this.piskelController.getPiskel().setDescriptor(d)},a.SaveController.prototype.onSaveSuccess_=function(){$.publish(Events.CLOSE_SETTINGS_DRAWER),$.publish(Events.SHOW_NOTIFICATION,[{content:"Successfully saved !"}]),$.publish(Events.PISKEL_SAVED)},a.SaveController.prototype.onSaveError_=function(a){$.publish(Events.SHOW_NOTIFICATION,[{content:"Saving failed ("+a+")"}])},a.SaveController.prototype.afterOnlineSaving_=function(){this.saveOnlineButton.attr("disabled",!1),this.saveOnlineStatus.html(""),this.afterSaving_()},a.SaveController.prototype.afterSaving_=function(){this.piskelName&&this.piskelName.classList.remove("piskel-name-saving"),window.setTimeout($.publish.bind($,Events.HIDE_NOTIFICATION),5e3)}}(),function(){var a=$.namespace("pskl.controller.settings");a.ImportController=function(a){this.piskelController=a,this.importedImage_=null},a.ImportController.prototype.init=function(){this.browseLocalButton=document.querySelector(".browse-local-button"),this.browseLocalButton.addEventListener("click",this.onBrowseLocalClick_.bind(this)),this.hiddenFileInput=$("[name=file-upload-input]"),this.hiddenFileInput.change(this.onFileUploadChange_.bind(this)),this.fileInputButton=$(".file-input-button"),this.fileInputButton.click(this.onFileInputClick_.bind(this)),this.hiddenOpenPiskelInput=$("[name=open-piskel-input]"),this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this)),this.openPiskelInputButton=$(".open-piskel-button"),this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this)),this.prevSessionContainer=$(".previous-session"),this.previousSessionTemplate_=pskl.utils.Template.get("previous-session-info-template"),this.fillRestoreSession_()},a.ImportController.prototype.closeDrawer_=function(){$.publish(Events.CLOSE_SETTINGS_DRAWER)},a.ImportController.prototype.onFileUploadChange_=function(){this.importPictureFromFile_()},a.ImportController.prototype.onFileInputClick_=function(){this.hiddenFileInput.click()},a.ImportController.prototype.onOpenPiskelChange_=function(){var a=this.hiddenOpenPiskelInput.get(0).files;1==a.length&&this.openPiskelFile_(a[0])},a.ImportController.prototype.onOpenPiskelClick_=function(){this.hiddenOpenPiskelInput.click()},a.ImportController.prototype.onBrowseLocalClick_=function(){$.publish(Events.DIALOG_DISPLAY,"browse-local"),this.closeDrawer_()},a.ImportController.prototype.openPiskelFile_=function(a){this.isPiskel_(a)&&(pskl.utils.PiskelFileUtils.loadFromFile(a,function(a,b,c){a.setDescriptor(b),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(c)}),this.closeDrawer_())},a.ImportController.prototype.importPictureFromFile_=function(){var a=this.hiddenFileInput.get(0).files;if(1==a.length){var b=a[0];if(!this.isImage_(b))throw this.closeDrawer_(),"File is not an image : "+b.type;$.publish(Events.DIALOG_DISPLAY,{dialogId:"import-image",initArgs:b}),this.closeDrawer_()}},a.ImportController.prototype.isImage_=function(a){return 0===a.type.indexOf("image")},a.ImportController.prototype.isPiskel_=function(a){return/\.piskel$/.test(a.name)},a.ImportController.prototype.fillRestoreSession_=function(){var a=pskl.app.backupService.getPreviousPiskelInfo();if(a){var b={name:a.name,date:pskl.utils.DateUtils.format(a.date,"{{H}}:{{m}} - {{Y}}/{{M}}/{{D}}")};this.prevSessionContainer.html(pskl.utils.Template.replace(this.previousSessionTemplate_,b)),$(".restore-session-button").click(this.onRestorePreviousSessionClick_.bind(this))}else this.prevSessionContainer.html("No piskel backup was found on this browser.")},a.ImportController.prototype.onRestorePreviousSessionClick_=function(){window.confirm("This will erase your current workspace. Continue ?")&&(pskl.app.backupService.load(),$.publish(Events.CLOSE_SETTINGS_DRAWER))}}(),function(){var a=$.namespace("pskl.controller.settings"),b={user:{template:"templates/settings/application.html",controller:a.ApplicationSettingsController},resize:{template:"templates/settings/resize.html",controller:a.ResizeController},"export":{template:"templates/settings/export.html",controller:a.ImageExportController},"import":{template:"templates/settings/import.html",controller:a.ImportController},localstorage:{template:"templates/settings/localstorage.html",controller:a.LocalStorageController},save:{template:"templates/settings/save.html",controller:a.SaveController}},c="has-expanded-drawer",d="expanded";a.SettingsController=function(a){this.piskelController=a,this.drawerContainer=document.getElementById("drawer-container"),this.settingsContainer=$("[data-pskl-controller=settings]"),this.isExpanded=!1,this.currentSetting=null},a.SettingsController.prototype.init=function(){$("[data-setting]").click(this.onSettingIconClick.bind(this)),$("body").click(this.onBodyClick.bind(this)),$.subscribe(Events.CLOSE_SETTINGS_DRAWER,this.closeDrawer.bind(this))},a.SettingsController.prototype.onSettingIconClick=function(a){var b=a.originalEvent.currentTarget,c=b.getAttribute("data-setting");this.currentSetting!=c?this.loadSetting(c):this.closeDrawer(),a.originalEvent.stopPropagation(),a.originalEvent.preventDefault()},a.SettingsController.prototype.onBodyClick=function(a){var b=a.target,c=pskl.utils.Dom.isParent(b,this.drawerContainer),d=b.getAttribute("data-setting"),e=c||d;this.isExpanded&&!e&&this.closeDrawer()},a.SettingsController.prototype.loadSetting=function(a){this.drawerContainer.innerHTML=pskl.utils.Template.get(b[a].template),new b[a].controller(this.piskelController).init(),this.settingsContainer.addClass(d),$("."+c).removeClass(c),$("[data-setting="+a+"]").addClass(c),this.isExpanded=!0,this.currentSetting=a},a.SettingsController.prototype.closeDrawer=function(){this.settingsContainer.removeClass(d),$("."+c).removeClass(c),this.isExpanded=!1,this.currentSetting=null,document.activeElement.blur()}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.AbstractDialogController=function(){},a.AbstractDialogController.prototype.init=function(){this.closeButton=document.querySelector(".dialog-close"),this.closeButton.addEventListener("click",this.closeDialog.bind(this))},a.AbstractDialogController.prototype.destroy=function(){},a.AbstractDialogController.prototype.closeDialog=function(){this.destroy(),$.publish(Events.DIALOG_HIDE)}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.CreatePaletteController=function(){this.paletteService=pskl.app.paletteService,this.paletteImportService=pskl.app.paletteImportService,this.selectedIndex=-1},pskl.utils.inherit(a.CreatePaletteController,a.AbstractDialogController),a.CreatePaletteController.prototype.init=function(a){this.superclass.init.call(this),this.colorsList=document.querySelector(".colors-list"),this.colorPreviewEl=document.querySelector(".color-preview"),this.hiddenFileInput=document.querySelector(".create-palette-import-input"),this.nameInput=document.querySelector('input[name="palette-name"]');var b=document.querySelector(".create-palette-submit"),c=document.querySelector(".create-palette-cancel"),d=document.querySelector(".create-palette-import-button");this.colorsList.addEventListener("click",this.onColorContainerClick_.bind(this)),this.nameInput.addEventListener("input",this.onNameInputChange_.bind(this)),this.hiddenFileInput.addEventListener("change",this.onFileInputChange_.bind(this)),b.addEventListener("click",this.onSubmitButtonClick_.bind(this)),c.addEventListener("click",this.closeDialog.bind(this)),d.addEventListener("click",this.onImportFileButtonClick_.bind(this));var e=document.querySelector(".color-picker-container");this.hslRgbColorPicker=new pskl.controller.widgets.HslRgbColorPicker(e,this.onColorUpdated_.bind(this)),this.hslRgbColorPicker.init();var f;if(a){var g=this.paletteService.getPaletteById(a);f=pskl.model.Palette.fromObject(g)}else f=new pskl.model.Palette(pskl.utils.Uuid.generate(),"New palette",[]);this.setPalette_(f)},a.CreatePaletteController.prototype.setPalette_=function(a){this.palette=a,this.nameInput.value=pskl.utils.unescapeHtml(this.palette.name),this.refresh_()},a.CreatePaletteController.prototype.destroy=function(){this.colorsList=null,this.colorPreviewEl=null,this.nameInput=null},a.CreatePaletteController.prototype.onColorUpdated_=function(a){var b=a.toRgbString();this.colorPreviewEl.style.background=b,this.palette&&(this.palette.set(this.selectedIndex,b),this.refreshColorElement_(this.selectedIndex))},a.CreatePaletteController.prototype.refreshColorElement_=function(a){var b=this.palette.get(this.selectedIndex),c=document.querySelector('[data-palette-index="'+a+'"]');c&&(c.style.background=b,c.classList.toggle("light-color",this.isLight_(b)))},a.CreatePaletteController.prototype.onColorContainerClick_=function(a){var b=a.target;b.classList.contains("create-palette-color")?this.onPaletteColorClick_(a,b):b.classList.contains("create-palette-new-color")?this.onNewColorClick_(a,b):b.classList.contains("create-palette-remove-color")&&this.onRemoveColorClick_(a,b),this.refresh_()},a.CreatePaletteController.prototype.onPaletteColorClick_=function(a,b){var c=parseInt(b.dataset.paletteIndex,10);this.selectColor_(c)},a.CreatePaletteController.prototype.onRemoveColorClick_=function(a,b){var c=b.parentNode,d=parseInt(c.dataset.paletteIndex,10);this.removeColor_(d)},a.CreatePaletteController.prototype.onNewColorClick_=function(){var a=this.palette.get(this.selectedIndex)||"#000000";this.palette.add(a),this.selectColor_(this.palette.size()-1)},a.CreatePaletteController.prototype.onSubmitButtonClick_=function(){this.paletteService.savePalette(this.palette),this.closeDialog()},a.CreatePaletteController.prototype.onImportFileButtonClick_=function(){this.hiddenFileInput.click()},a.CreatePaletteController.prototype.onFileInputChange_=function(){var a=this.hiddenFileInput.files;1==a.length&&this.paletteImportService.read(a[0],this.setPalette_.bind(this))},a.CreatePaletteController.prototype.onNameInputChange_=function(){this.palette.name=pskl.utils.escapeHtml(this.nameInput.value)},a.CreatePaletteController.prototype.selectColor_=function(a){this.selectedIndex=a,this.hslRgbColorPicker.setColor(this.palette.get(a))},a.CreatePaletteController.prototype.removeColor_=function(a){this.palette.removeAt(a),this.refresh_()},a.CreatePaletteController.prototype.refresh_=function(){var a="",b=pskl.utils.Template.get("create-palette-color-template"),c=this.palette.colors;c.forEach(function(c,d){var e=d===this.selectedIndex;a+=pskl.utils.Template.replace(b,{color:c,index:d,":selected":e,":light-color":this.isLight_(c)})}.bind(this)),a+='
      • +
      • ',this.colorsList.innerHTML=a,$(".colors-list").sortable({placeholder:"colors-list-drop-proxy",update:this.onDrop_.bind(this),items:".create-palette-color"})},a.CreatePaletteController.prototype.isLight_=function(a){var b=window.tinycolor(a).toRgb();return b.r+b.b+b.g>384},a.CreatePaletteController.prototype.onDrop_=function(a,b){var c=b.item.get(0),d=parseInt(c.dataset.paletteIndex,10),e=$(".create-palette-color").index(b.item);this.palette.move(d,e),this.selectedIndex=e,this.refresh_()}}(),function(){var a=$.namespace("pskl.controller.dialogs"),b=60;a.ImportImageController=function(){this.importedImage_=null,this.file_=null},pskl.utils.inherit(a.ImportImageController,a.AbstractDialogController),a.ImportImageController.prototype.init=function(a){this.superclass.init.call(this),this.file_=a,this.importPreview=$(".import-section-preview"),this.fileNameContainer=$(".import-image-file-name"),this.resizeWidth=$("[name=resize-width]"),this.resizeHeight=$("[name=resize-height]"),this.smoothResize=$("[name=smooth-resize-checkbox]"),this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this,"width")),this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this,"height")),this.importImageForm=$("[name=import-image-form]"),this.importImageForm.submit(this.onImportFormSubmit_.bind(this)),pskl.utils.FileUtils.readImageFile(this.file_,this.onImageLoaded_.bind(this))},a.ImportImageController.prototype.onImportFormSubmit_=function(a){a.originalEvent.preventDefault(),this.importImageToPiskel_()},a.ImportImageController.prototype.onResizeInputKeyUp_=function(a,b){this.importedImage_&&this.synchronizeResizeFields_(b.target.value,a)},a.ImportImageController.prototype.synchronizeResizeFields_=function(a,b){a=parseInt(a,10),isNaN(a)&&(a=0);var c=this.importedImage_.height,d=this.importedImage_.width;"width"===b?this.resizeHeight.val(Math.round(a*c/d)):this.resizeWidth.val(Math.round(a*d/c))},a.ImportImageController.prototype.onImageLoaded_=function(a){this.importedImage_=a;var b=this.importedImage_.width,c=this.importedImage_.height;this.importedImage_.onload=function(){};var d=this.extractFileNameFromPath_(this.file_.name);this.fileNameContainer.html(d),this.resizeWidth.val(b),this.resizeHeight.val(c),this.importPreview.width("auto"),this.importPreview.html(""),this.importPreview.append(this.createImagePreview_())},a.ImportImageController.prototype.createImagePreview_=function(){var a=document.createElement("IMG");return a.src=this.importedImage_.src,a.setAttribute("height",b),a},a.ImportImageController.prototype.extractFileNameFromPath_=function(a){var b=[];return b=-1!==a.indexOf("/")?a.split("/"):-1!==a.indexOf("\\")?a.split("\\"):[a],b[b.length-1]},a.ImportImageController.prototype.importImageToPiskel_=function(){var a=this.importedImage_;if(a&&window.confirm("You are about to create a new Piskel, unsaved changes will be lost.")){var b=new window.SuperGif({gif:a});b.load({success:function(){var a=b.getFrames().map(function(a){return pskl.CanvasUtils.createFromImageData(a.data)});this.createPiskelFromImages_(a),this.closeDialog()}.bind(this),error:function(){this.createPiskelFromImages_([a]),this.closeDialog()}.bind(this)})}},a.ImportImageController.prototype.createFramesFromImages_=function(a){var b=this.resizeWidth.val(),c=this.resizeHeight.val(),d=!!this.smoothResize.prop("checked"),e=a.map(function(a){var e=pskl.utils.ImageResizer.resize(a,b,c,d);return pskl.utils.FrameUtils.createFromImage(e)});return e},a.ImportImageController.prototype.createPiskelFromImages_=function(a){var b=this.createFramesFromImages_(a),c=pskl.model.Layer.fromFrames("Layer 1",b),d=new pskl.model.piskel.Descriptor("Imported piskel",""),e=pskl.model.Piskel.fromLayers([c],d);pskl.app.piskelController.setPiskel(e),pskl.app.animationController.setFPS(Constants.DEFAULT.FPS)}}(),function(){var a=$.namespace("pskl.controller.dialogs");a.BrowseLocalController=function(){},pskl.utils.inherit(a.BrowseLocalController,a.AbstractDialogController),a.BrowseLocalController.prototype.init=function(){this.superclass.init.call(this),this.localStorageItemTemplate_=pskl.utils.Template.get("local-storage-item-template"),this.service_=pskl.app.localStorageService,this.piskelList=$(".local-piskel-list"),this.prevSessionContainer=$(".previous-session"),this.fillLocalPiskelsList_(),this.piskelList.click(this.onPiskelsListClick_.bind(this))},a.BrowseLocalController.prototype.onPiskelsListClick_=function(a){var b=a.target.getAttribute("data-action"),c=a.target.getAttribute("data-name");"load"===b?window.confirm("This will erase your current piskel. Continue ?")&&(this.service_.load(c),this.closeDialog()):"delete"===b&&window.confirm("This will permanently DELETE this piskel from your computer. Continue ?")&&(this.service_.remove(c),this.fillLocalPiskelsList_())},a.BrowseLocalController.prototype.fillLocalPiskelsList_=function(){var a="",b=this.service_.getKeys();b.sort(function(a,b){return a.dateb.date?-1:0}),b.forEach(function(b){var c=pskl.utils.DateUtils.format(b.date,"{{Y}}/{{M}}/{{D}} {{H}}:{{m}}");a+=pskl.utils.Template.replace(this.localStorageItemTemplate_,{name:b.name,date:c})}.bind(this));var c=this.piskelList.get(0).tBodies[0];c.innerHTML=a}}(),function(){var a=$.namespace("pskl.controller.dialogs"),b={"create-palette":{template:"templates/dialogs/create-palette.html",controller:a.CreatePaletteController},"browse-local":{template:"templates/dialogs/browse-local.html",controller:a.BrowseLocalController},"import-image":{template:"templates/dialogs/import-image.html",controller:a.ImportImageController}};a.DialogsController=function(a){this.piskelController=a,this.currentDialog_=null},a.DialogsController.prototype.init=function(){this.dialogContainer_=document.getElementById("dialog-container"),this.dialogWrapper_=document.getElementById("dialog-container-wrapper"),$.subscribe(Events.DIALOG_DISPLAY,this.onDialogDisplayEvent_.bind(this)),$.subscribe(Events.DIALOG_HIDE,this.onDialogHideEvent_.bind(this)),pskl.app.shortcutService.addShortcut("alt+P",this.onDialogDisplayEvent_.bind(this,null,"create-palettes")),this.dialogWrapper_.classList.add("animated")},a.DialogsController.prototype.onDialogDisplayEvent_=function(a,c){var d,e;if("string"==typeof c?d=c:(d=c.dialogId,e=c.initArgs),!this.isDisplayed()){var f=b[d];if(f){this.dialogContainer_.classList.add(d),this.dialogContainer_.innerHTML=pskl.utils.Template.get(f.template);var g=new f.controller(this.piskelController);g.init(e),this.showDialogWrapper_(),this.currentDialog_={id:d,controller:g}}else console.error("Could not find dialog configuration for dialogId : "+d)}},a.DialogsController.prototype.onDialogHideEvent_=function(){this.hideDialog()},a.DialogsController.prototype.showDialogWrapper_=function(){pskl.app.shortcutService.addShortcut("ESC",this.hideDialog.bind(this)),this.dialogWrapper_.classList.add("show")},a.DialogsController.prototype.hideDialog=function(){var a=this.currentDialog_;if(a){a.controller.destroy();var b=this.currentDialog_.id;window.setTimeout(function(){this.dialogContainer_.classList.remove(b)}.bind(this),800)}this.hideDialogWrapper_(),this.currentDialog_=null},a.DialogsController.prototype.hideDialogWrapper_=function(){pskl.app.shortcutService.removeShortcut("ESC"),this.dialogWrapper_.classList.remove("show")},a.DialogsController.prototype.isDisplayed=function(){return null!==this.currentDialog_}}(),function(){var a=$.namespace("pskl.controller.widgets");a.HslRgbColorPicker=function(a,b){this.container=a,this.colorUpdatedCallback=b,this.lastInputTimestamp_=0},a.HslRgbColorPicker.prototype.init=function(){var a=pskl.utils.UserAgent.isChrome||pskl.utils.UserAgent.isFirefox,b=a?"input":"change";this.container.addEventListener(b,this.onPickerChange_.bind(this)),this.spectrumEl=this.container.querySelector(".color-picker-spectrum"),$(this.spectrumEl).spectrum({flat:!0,showInput:!0,showButtons:!1,move:this.setColor.bind(this),change:this.setColor.bind(this)}),this.setColor("#000000")},a.HslRgbColorPicker.prototype.onPickerChange_=function(a){var b=a.target,c=b.dataset.model,d=b.dataset.dimension,e=parseInt(b.value,10);("v"===d||"s"===d)&&(e/=100);var f;"rgb"===c?f=this.tinyColor.toRgb():"hsv"===c&&(f=this.hsvColor),isNaN(e)?e=f[d]:f[d]=e,this.setColor(f)},a.HslRgbColorPicker.prototype.setColor=function(a){this.unplugged||(this.unplugged=!0,this.hsvColor=this.toHsvColor_(a),this.tinyColor=this.toTinyColor_(a),this.updateInputs(),$(".color-picker-spectrum").spectrum("set",this.tinyColor),this.colorUpdatedCallback(this.tinyColor),this.unplugged=!1)},a.HslRgbColorPicker.prototype.updateInputs=function(){for(var a=this.container.querySelectorAll("input"),b=this.tinyColor.toRgb(),c=0;c";this.piskelController=a},a.LocalStorageService.prototype.init=function(){},a.LocalStorageService.prototype.save=function(a,b,c){this.removeFromKeys_(a),this.addToKeys_(a,b,Date.now()),window.localStorage.setItem("piskel."+a,c)},a.LocalStorageService.prototype.load=function(a){var b=this.getPiskel(a),c=(this.getKey_(a),JSON.parse(b)),d=c.piskel.fps,e=c.piskel.description;pskl.utils.serialization.Deserializer.deserialize(c,function(b){b.setDescriptor(new pskl.model.piskel.Descriptor(a,e,!0)),pskl.app.piskelController.setPiskel(b),pskl.app.animationController.setFPS(d)})},a.LocalStorageService.prototype.remove=function(a){this.removeFromKeys_(a),window.localStorage.removeItem("piskel."+a)},a.LocalStorageService.prototype.saveKeys_=function(a){window.localStorage.setItem("piskel.keys",JSON.stringify(a))},a.LocalStorageService.prototype.removeFromKeys_=function(a){var b=this.getKeys(),c=b.filter(function(b){return b.name!==a});this.saveKeys_(c)},a.LocalStorageService.prototype.getKey_=function(a){var b=this.getKeys().filter(function(b){return b.name===a});return b.length>0?b[0]:null},a.LocalStorageService.prototype.addToKeys_=function(a,b,c){var d=this.getKeys();d.push({name:a,description:b,date:c}),this.saveKeys_(d)},a.LocalStorageService.prototype.getPiskel=function(a){return window.localStorage.getItem("piskel."+a)},a.LocalStorageService.prototype.getKeys=function(){var a=window.localStorage.getItem("piskel.keys");return JSON.parse(a)||[]}}(),function(){var a=$.namespace("pskl.service");a.GithubStorageService=function(a){this.piskelController=a},a.GithubStorageService.prototype.init=function(){},a.GithubStorageService.prototype.store=function(){throw"Github save is no longer available. Use local save instead"}}(),function(){var a=$.namespace("pskl.service");a.AppEngineStorageService=function(a){this.piskelController=a},a.AppEngineStorageService.prototype.init=function(){},a.AppEngineStorageService.prototype.store=function(a){var b=this.piskelController.getPiskel(),c=b.getDescriptor(),d={framesheet:this.piskelController.serialize(),fps:this.piskelController.getFPS(),name:c.name,description:c.description,frames:this.piskelController.getFrameCount(),first_frame_as_png:pskl.app.getFirstFrameAsPng(),framesheet_as_png:pskl.app.getFramesheetAsPng()};c.isPublic&&(d["public"]=!0);var e=function(){a.success(),a.after()},f=function(b){a.error(b.status),a.after()};pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE,d,e,f)}}(),function(){var a=$.namespace("pskl.service"),b=6e4;a.BackupService=function(a){this.piskelController=a,this.lastHash=null},a.BackupService.prototype.init=function(){var a=window.localStorage.getItem("bkp.next.piskel"),c=window.localStorage.getItem("bkp.next.info");a&&c&&(window.localStorage.setItem("bkp.prev.piskel",a),window.localStorage.setItem("bkp.prev.info",c)),window.setInterval(this.backup.bind(this),b)},a.BackupService.prototype.backup=function(){var a=this.piskelController.getPiskel(),b=a.getDescriptor(),c=a.getHash(),d={name:b.name,description:b.info,fps:this.piskelController.getFPS(),date:Date.now(),hash:c}; -c!==this.lastHash&&(this.lastHash=c,window.localStorage.setItem("bkp.next.piskel",this.piskelController.serialize()),window.localStorage.setItem("bkp.next.info",JSON.stringify(d)))},a.BackupService.prototype.getPreviousPiskelInfo=function(){var a=window.localStorage.getItem("bkp.prev.info");return a?JSON.parse(a):void 0},a.BackupService.prototype.load=function(){var a=window.localStorage.getItem("bkp.prev.piskel"),b=window.localStorage.getItem("bkp.prev.info");a=JSON.parse(a),b=JSON.parse(b),pskl.utils.serialization.Deserializer.deserialize(a,function(a){a.setDescriptor(new pskl.model.piskel.Descriptor(b.name,b.description,!0)),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(b.fps)})}}(),function(){var a=$.namespace("pskl.service");a.BeforeUnloadService=function(a){this.piskelController=a},a.BeforeUnloadService.prototype.init=function(){window.addEventListener("beforeunload",this.onBeforeUnload.bind(this))},a.BeforeUnloadService.prototype.onBeforeUnload=function(a){if(pskl.app.backupService.backup(),pskl.app.savedStatusService.isDirty()){var b="Your Piskel seems to have unsaved changes";return(a||window.event).returnValue=b,b}}}(),function(){var a=$.namespace("pskl.service");a.HistoryService=function(a,b,c){this.piskelController=a||pskl.app.piskelController,this.shortcutService=b||pskl.app.shortcutService,this.deserializer=c||pskl.utils.serialization.Deserializer,this.stateQueue=[],this.currentIndex=-1,this.lastLoadState=-1,this.saveNextAsSnapshot=!1},a.HistoryService.SNAPSHOT="SNAPSHOT",a.HistoryService.REPLAY="REPLAY",a.HistoryService.SNAPSHOT_PERIOD=50,a.HistoryService.LOAD_STATE_INTERVAL=50,a.HistoryService.REPLAY_NO_SNAPSHOT="REPLAY_NO_SNAPSHOT",a.HistoryService.prototype.init=function(){$.subscribe(Events.PISKEL_SAVE_STATE,this.onSaveStateEvent.bind(this)),this.shortcutService.addShortcut("ctrl+Z",this.undo.bind(this)),this.shortcutService.addShortcut("ctrl+Y",this.redo.bind(this)),this.saveState({type:a.HistoryService.SNAPSHOT})},a.HistoryService.prototype.onSaveStateEvent=function(a,b){this.saveState(b)},a.HistoryService.prototype.saveState=function(b){this.stateQueue=this.stateQueue.slice(0,this.currentIndex+1),this.currentIndex=this.currentIndex+1;var c={action:b,frameIndex:this.piskelController.currentFrameIndex,layerIndex:this.piskelController.currentLayerIndex},d=b.type===a.HistoryService.SNAPSHOT,e=b.type===a.HistoryService.REPLAY_NO_SNAPSHOT,f=this.currentIndex%a.HistoryService.SNAPSHOT_PERIOD===0||this.saveNextAsSnapshot;e&&f?this.saveNextAsSnapshot=!0:(d||f)&&(c.piskel=this.piskelController.serialize(!0),this.saveNextAsSnapshot=!1),this.stateQueue.push(c)},a.HistoryService.prototype.undo=function(){this.loadState(this.currentIndex-1)},a.HistoryService.prototype.redo=function(){this.loadState(this.currentIndex+1)},a.HistoryService.prototype.isLoadStateAllowed_=function(b){var c=Date.now()-this.lastLoadState>a.HistoryService.LOAD_STATE_INTERVAL,d=b>=0&&bb)throw"Could not find previous SNAPSHOT saved in history stateQueue";var c=this.getSnapshotFromState_(b),d=this.onPiskelLoaded_.bind(this,a,b);this.deserializer.deserialize(c,d)}}catch(e){window.console.error("[CRITICAL ERROR] : Unable to load a history state."),"string"==typeof e?window.console.error(e):(window.console.error(e.message),window.console.error(e.stack)),this.stateQueue=[],this.currentIndex=-1}},a.HistoryService.prototype.getSnapshotFromState_=function(a){var b=this.stateQueue[a],c=b.piskel;return"string"==typeof c&&(c=JSON.parse(c),b.piskel=c),c},a.HistoryService.prototype.onPiskelLoaded_=function(a,b,c){var d=this.getPiskelSize_();c.setDescriptor(this.piskelController.piskel.getDescriptor()),this.piskelController.setPiskel(c);for(var e=b+1;a>=e;e++){var f=this.stateQueue[e];this.setupState(f),this.replayState(f)}var g=this.stateQueue[a+1];g&&this.setupState(g),this.currentIndex=a,$.publish(Events.PISKEL_RESET),d!==this.getPiskelSize_()&&$.publish(Events.FRAME_SIZE_CHANGED)},a.HistoryService.prototype.getPiskelSize_=function(){return this.piskelController.getWidth()+"x"+this.piskelController.getHeight()},a.HistoryService.prototype.setupState=function(a){this.piskelController.setCurrentFrameIndex(a.frameIndex),this.piskelController.setCurrentLayerIndex(a.layerIndex)},a.HistoryService.prototype.replayState=function(a){var b=a.action,c=(b.type,this.piskelController.getLayerAt(a.layerIndex)),d=c.getFrameAt(a.frameIndex);b.scope.replay(d,b.replay)}}(),function(){var a=$.namespace("pskl.service.palette");a.PaletteService=function(){this.palettes=[],this.localStorageService=window.localStorage},a.PaletteService.prototype.getPalettes=function(){var a=this.localStorageService.getItem("piskel.palettes");return JSON.parse(a)||[]},a.PaletteService.prototype.getPaletteById=function(a){var b=this.getPalettes();return this.findPaletteInArray_(a,b)},a.PaletteService.prototype.savePalette=function(a){var b=this.getPalettes(),c=this.findPaletteInArray_(a.id,b);if(c){var d=b.indexOf(c);b.splice(d,1,a)}else b.push(a);this.savePalettes_(b),$.publish(Events.SHOW_NOTIFICATION,[{content:"Palette "+a.name+" successfully saved !"}]),window.setTimeout($.publish.bind($,Events.HIDE_NOTIFICATION),2e3)},a.PaletteService.prototype.deletePaletteById=function(a){var b=this.getPalettes(),c=b.filter(function(b){return b.id!==a});this.savePalettes_(c)},a.PaletteService.prototype.savePalettes_=function(a){this.localStorageService.setItem("piskel.palettes",JSON.stringify(a)),$.publish(Events.PALETTE_LIST_UPDATED)},a.PaletteService.prototype.findPaletteInArray_=function(a,b){var c=null;return b.forEach(function(b){b.id===a&&(c=b)}),c}}(),function(){var a=$.namespace("pskl.service.palette"),b=["gpl"];a.PaletteImportService=function(){},a.PaletteImportService.prototype.read=function(b,c,d){var e;if(this.isImage_(b)?e=new a.PaletteImageReader(b,c,d):this.isSupportedFormat_(b)&&(e=this.getFileReader_(b,c,d)),!e)throw"Could not find reader for file : "+b.name;e.read()},a.PaletteImportService.prototype.isImage_=function(a){return 0===a.type.indexOf("image")},a.PaletteImportService.prototype.getFileReader_=function(b,c,d){var e=this.getExtension_(b);return"gpl"===e?new a.PaletteGplReader(b,c,d):void 0},a.PaletteImportService.prototype.isSupportedFormat_=function(a){var c=this.getExtension_(a);return-1!=b.indexOf(c)},a.PaletteImportService.prototype.getExtension_=function(a){var b=a.name.split(".");return b[b.length-1]}}(),function(){var a=$.namespace("pskl.service.palette"),b=/^(\d{1,3}\s+)(\d{1,3}\s+)(\d{1,3}\s+)/,c=/^name\s*\:\s*(.*)$/i;a.PaletteGplReader=function(a,b,c){this.file=a,this.onSuccess=b,this.onError=c},a.PaletteGplReader.prototype.read=function(){pskl.utils.FileUtils.readFile(this.file,this.onFileLoaded_.bind(this))},a.PaletteGplReader.prototype.onFileLoaded_=function(a){var d=pskl.utils.Base64.toText(a),e=d.match(/[^\r\n]+/g),f=e.map(function(a){var b=a.match(c);return b?b[1]:""}).join(""),g=e.filter(function(a){return b.test(a)}),h=g.map(function(a){var c=a.match(b),d=window.tinycolor({r:parseInt(c[1],10),g:parseInt(c[2],10),b:parseInt(c[3],10)});return d.toRgbString()});if(f&&h.length){var i=pskl.utils.Uuid.generate(),j=new pskl.model.Palette(i,f,h);this.onSuccess(j)}else this.onError()}}(),function(){var a=$.namespace("pskl.service.palette");a.PaletteImageReader=function(a,b,c){this.file=a,this.onSuccess=b,this.onError=c},a.PaletteImageReader.prototype.read=function(){pskl.utils.FileUtils.readImageFile(this.file,this.onImageLoaded_.bind(this))},a.PaletteImageReader.prototype.onImageLoaded_=function(a){var b=pskl.utils.FrameUtils.createFromImage(a),c={};b.forEachPixel(function(a){c[a]=!0}),delete c[Constants.TRANSPARENT_COLOR];var d=Object.keys(c),e=pskl.utils.Uuid.generate(),f=new pskl.model.Palette(e,this.file.name+" palette",d);this.onSuccess(f)}}(),function(){var a=$.namespace("pskl.service");a.SavedStatusService=function(a){this.piskelController=a},a.SavedStatusService.prototype.init=function(){$.subscribe(Events.TOOL_RELEASED,this.onToolReleased.bind(this)),$.subscribe(Events.PISKEL_RESET,this.onPiskelReset.bind(this)),$.subscribe(Events.PISKEL_SAVED,this.onPiskelSaved.bind(this))},a.SavedStatusService.prototype.onPiskelReset=function(){var a=this.piskelController.getPiskel();a.firstResetDone_?this.updateDirtyStatus(!0):a.firstResetDone_=!0},a.SavedStatusService.prototype.onToolReleased=function(){this.updateDirtyStatus(!0)},a.SavedStatusService.prototype.onPiskelSaved=function(){this.updateDirtyStatus(!1)},a.SavedStatusService.prototype.updateDirtyStatus=function(a){var b=this.piskelController.getPiskel();b.isDirty_!==a&&(b.isDirty_=a,this.updatePiskelName())},a.SavedStatusService.prototype.updatePiskelName=function(){var a=this.piskelController.getPiskel(),b=a.getDescriptor().name;$(".piskel-name").html(a.isDirty_?b+" *":b)},a.SavedStatusService.prototype.isDirty=function(){var a=this.piskelController.getPiskel();return a.isDirty_}}(),function(){var a=$.namespace("pskl.service.keyboard");a.ShortcutService=function(){this.shortcuts_={}},a.ShortcutService.prototype.init=function(){$(document.body).keydown($.proxy(this.onKeyUp_,this))},a.ShortcutService.prototype.addShortcut=function(a,b){var c=this.parseKey_(a.toLowerCase()),d=c.key,e=c.meta;if(this.shortcuts_[d]=this.shortcuts_[d]||{},this.shortcuts_[d][e]){var f=("normal"!==e?e+" + ":"")+d;console.error("[ShortcutService] >>> Shortcut ["+f+"] already registered")}else this.shortcuts_[d][e]=b},a.ShortcutService.prototype.removeShortcut=function(a){var b=this.parseKey_(a.toLowerCase()),c=b.key,d=b.meta;this.shortcuts_[c]=this.shortcuts_[c]||{},this.shortcuts_[c][d]=null},a.ShortcutService.prototype.parseKey_=function(a){var b=this.getMetaKey_({alt:-1!=a.indexOf("alt+"),shift:-1!=a.indexOf("shift+"),ctrl:-1!=a.indexOf("ctrl+")}),c=a.split(/\+(?!$)/);return a=c[c.length-1],{meta:b,key:a}},a.ShortcutService.prototype.getMetaKey_=function(a){var b=[];return["alt","ctrl","shift"].forEach(function(c){a[c]&&b.push(c)}),b.length>0?b.join("+"):"normal"},a.ShortcutService.prototype.onKeyUp_=function(a){if(!this.isInInput_(a)){var b=a.which,c=(a.target.nodeName.toUpperCase(),pskl.service.keyboard.KeycodeTranslator.toChar(b)),d=this.shortcuts_[c];if(d){var e=this.getMetaKey_({alt:this.isAltKeyPressed_(a),shift:this.isShiftKeyPressed_(a),ctrl:this.isCtrlKeyPressed_(a)}),f=d[e];if(f){var g=f(c);g!==!0&&a.preventDefault()}}}},a.ShortcutService.prototype.isInInput_=function(a){var b=a.target.nodeName.toUpperCase();return"INPUT"===b||"TEXTAREA"===b},a.ShortcutService.prototype.isCtrlKeyPressed_=function(a){return pskl.utils.UserAgent.isMac?a.metaKey:a.ctrlKey},a.ShortcutService.prototype.isShiftKeyPressed_=function(a){return a.shiftKey},a.ShortcutService.prototype.isAltKeyPressed_=function(a){return a.altKey}}(),function(){var a={191:"?",8:"back",27:"esc",38:"up",40:"down",46:"del",189:"-",187:"+"},b=$.namespace("pskl.service.keyboard");b.KeycodeTranslator={toChar:function(b){return b>=48&&57>=b?b-48+"":b>=65&&90>=b?(b-65+10).toString(36):a[b]}}}(),function(){var a=$.namespace("pskl.service.keyboard");a.CheatsheetService=function(){this.isDisplayed_=!1},a.CheatsheetService.prototype.init=function(){if(this.cheatsheetEl_=document.getElementById("cheatsheet-wrapper"),!this.cheatsheetEl_)throw"cheatsheetEl_ DOM element could not be retrieved";this.initMarkup_(),pskl.app.shortcutService.addShortcut("shift+?",this.toggleCheatsheet_.bind(this)),pskl.app.shortcutService.addShortcut("?",this.toggleCheatsheet_.bind(this));var a=$(".cheatsheet-link");a.click(this.toggleCheatsheet_.bind(this)),$.subscribe(Events.TOGGLE_HELP,this.toggleCheatsheet_.bind(this)),$.subscribe(Events.ESCAPE,this.onEscape_.bind(this))},a.CheatsheetService.prototype.toggleCheatsheet_=function(){this.isDisplayed_?this.hideCheatsheet_():this.showCheatsheet_()},a.CheatsheetService.prototype.onEscape_=function(){this.isDisplayed_&&this.hideCheatsheet_()},a.CheatsheetService.prototype.showCheatsheet_=function(){pskl.app.shortcutService.addShortcut("ESC",this.hideCheatsheet_.bind(this)),this.cheatsheetEl_.style.display="block",this.isDisplayed_=!0},a.CheatsheetService.prototype.hideCheatsheet_=function(){pskl.app.shortcutService.removeShortcut("ESC"),this.cheatsheetEl_.style.display="none",this.isDisplayed_=!1},a.CheatsheetService.prototype.initMarkup_=function(){this.initMarkupForTools_(),this.initMarkupForMisc_(),this.initMarkupForSelection_()},a.CheatsheetService.prototype.toDescriptor_=function(a,b,c){return pskl.utils.UserAgent.isMac&&(a=a.replace("ctrl","cmd")),{shortcut:a,description:b,icon:c}},a.CheatsheetService.prototype.getDomFromDescriptor_=function(a){var b=pskl.utils.Template.get("cheatsheet-shortcut-template"),c=pskl.utils.Template.replace(b,{shortcutIcon:a.icon,shortcutDescription:a.description,shortcutKey:a.shortcut});return pskl.utils.Template.createFromHTML(c)},a.CheatsheetService.prototype.initMarkupAbstract_=function(a,b){for(var c=$(b,this.cheatsheetEl_).get(0),d=0;da?1:-1,i=d>c?1:-1,j=f-g;;){if(e.push({col:a,row:c}),a==b&&c==d)break;var k=2*j;k>-g&&(j-=g,a+=h),f>k&&(j+=f,c+=i)}return e}}(),function(){var a=$.namespace("pskl.drawingtools");a.ShapeTool=function(){this.startCol=null,this.startRow=null,this.tooltipDescriptors=[{key:"shift",description:"Keep 1 to 1 ratio"}]},pskl.utils.inherit(a.ShapeTool,a.BaseTool),a.ShapeTool.prototype.applyToolAt=function(a,b,c,d,e){$.publish(Events.DRAG_START,[a,b]),this.startCol=a,this.startRow=b,e.setPixel(a,b,c)},a.ShapeTool.prototype.moveToolAt=function(a,b,c,d,e,f){var g=this.getCoordinates_(a,b,f);$.publish(Events.CURSOR_MOVED,[g.col,g.row]),e.clear(),c==Constants.TRANSPARENT_COLOR&&(c=Constants.SELECTION_TRANSPARENT_COLOR),this.draw_(g.col,g.row,c,e)},a.ShapeTool.prototype.releaseToolAt=function(a,b,c,d,e,f){e.clear();var g=this.getCoordinates_(a,b,f);this.draw_(g.col,g.row,c,d),$.publish(Events.DRAG_END,[a,b]),this.raiseSaveStateEvent({col:a,row:b,startCol:this.startCol,startRow:this.startRow,color:c})},a.ShapeTool.prototype.replay=function(a,b){this.startCol=b.startCol,this.startRow=b.startRow,this.draw_(b.col,b.row,b.color,a)},a.ShapeTool.prototype.getCoordinates_=function(a,b,c){return c.shiftKey?this.getScaledCoordinates_(a,b):{col:a,row:b}},a.ShapeTool.prototype.getScaledCoordinates_=function(a,b){var c=this.startCol-a,d=Math.abs(c),e=this.startRow-b,f=Math.abs(e),g=Math.min(d,f);return b=this.startRow-e/f*g,a=this.startCol-c/d*g,{col:a,row:b}},a.ShapeTool.prototype.draw_=Constants.ABSTRACT_FUNCTION}(),function(){var a=$.namespace("pskl.drawingtools");a.SimplePen=function(){this.toolId="tool-pen",this.helpText="Pen tool",this.previousCol=null,this.previousRow=null,this.pixels=[]},pskl.utils.inherit(a.SimplePen,a.BaseTool),a.SimplePen.prototype.applyToolAt=function(a,b,c,d,e){this.previousCol=a,this.previousRow=b,e.setPixel(a,b,c),c===Constants.TRANSPARENT_COLOR&&d.setPixel(a,b,c),this.pixels.push({col:a,row:b,color:c})},a.SimplePen.prototype.moveToolAt=function(a,b,c,d,e,f){if(Math.abs(a-this.previousCol)>1||Math.abs(b-this.previousRow)>1)for(var g=this.getLinePixels_(a,this.previousCol,b,this.previousRow),h=0,i=g.length;i>h;h++){var j=g[h];this.applyToolAt(j.col,j.row,c,d,e,f)}else this.applyToolAt(a,b,c,d,e,f);this.previousCol=a,this.previousRow=b},a.SimplePen.prototype.releaseToolAt=function(a,b,c,d){this.setPixelsToFrame_(d,this.pixels),this.raiseSaveStateEvent({pixels:this.pixels.slice(0),color:c}),this.resetUsedPixels_()},a.SimplePen.prototype.replay=function(a,b){this.setPixelsToFrame_(a,b.pixels,b.color)},a.SimplePen.prototype.setPixelsToFrame_=function(a,b){b.forEach(function(b){a.setPixel(b.col,b.row,b.color)})},a.SimplePen.prototype.resetUsedPixels_=function(){this.pixels=[]}}(),function(){var a=$.namespace("pskl.drawingtools"),b=3;a.Lighten=function(){this.superclass.constructor.call(this),this.toolId="tool-lighten",this.helpText="Lighten",this.tooltipDescriptors=[{key:"ctrl",description:"Darken"},{key:"shift",description:"Apply only once per pixel"}],this.usedPixels_={darken:{},lighten:{}}},pskl.utils.inherit(a.Lighten,a.SimplePen),a.Lighten.prototype.resetUsedPixels_=function(){this.usedPixels_={darken:{},lighten:{}},this.superclass.resetUsedPixels_.call(this)},a.Lighten.prototype.applyToolAt=function(a,c,d,e,f,g){var h=f.getPixel(a,c),i=e.getPixel(a,c),j=h===Constants.TRANSPARENT_COLOR?i:h,k=pskl.utils.UserAgent.isMac?g.metaKey:g.ctrlKey,l=g.shiftKey,m=j===Constants.TRANSPARENT_COLOR,n=k?this.usedPixels_.darken:this.usedPixels_.lighten,o=a+"-"+c,p=m||l&&n[o];if(p)d=window.tinycolor(j);else{var q=l?2*b:b;d=k?window.tinycolor.darken(j,q):window.tinycolor.lighten(j,q)}d&&(n[o]=!0,this.superclass.applyToolAt.call(this,a,c,d.toRgbString(),e,f,g))}}(),function(){var a=$.namespace("pskl.drawingtools");a.VerticalMirrorPen=function(){this.superclass.constructor.call(this),this.toolId="tool-vertical-mirror-pen",this.helpText="Vertical Mirror pen",this.tooltipDescriptors=[{key:"ctrl",description:"Use horizontal axis"},{key:"shift",description:"Use horizontal and vertical axis"}]},pskl.utils.inherit(a.VerticalMirrorPen,a.SimplePen),a.VerticalMirrorPen.prototype.backupPreviousPositions_=function(){this.backupPreviousCol=this.previousCol,this.backupPreviousRow=this.previousRow},a.VerticalMirrorPen.prototype.restorePreviousPositions_=function(){this.previousCol=this.backupPreviousCol,this.previousRow=this.backupPreviousRow},a.VerticalMirrorPen.prototype.applyToolAt=function(a,b,c,d,e,f){this.superclass.applyToolAt.call(this,a,b,c,d,e),this.backupPreviousPositions_();var g=this.getSymmetricCol_(a,d),h=this.getSymmetricRow_(b,d),i=pskl.utils.UserAgent.isMac?f.metaKey:f.ctrlKey;i||this.superclass.applyToolAt.call(this,g,b,c,d,e),(f.shiftKey||i)&&this.superclass.applyToolAt.call(this,a,h,c,d,e),f.shiftKey&&this.superclass.applyToolAt.call(this,g,h,c,d,e),this.restorePreviousPositions_()},a.VerticalMirrorPen.prototype.getSymmetricCol_=function(a,b){return b.getWidth()-a-1},a.VerticalMirrorPen.prototype.getSymmetricRow_=function(a,b){return b.getHeight()-a-1}}(),function(){var a=$.namespace("pskl.drawingtools");a.Eraser=function(){this.superclass.constructor.call(this),this.toolId="tool-eraser",this.helpText="Eraser tool"},pskl.utils.inherit(a.Eraser,a.SimplePen),a.Eraser.prototype.applyToolAt=function(a,b,c,d,e,f){this.superclass.applyToolAt.call(this,a,b,Constants.TRANSPARENT_COLOR,d,e,f)},a.Eraser.prototype.releaseToolAt=function(a,b,c,d,e,f){this.superclass.releaseToolAt.call(this,a,b,Constants.TRANSPARENT_COLOR,d,e,f)}}(),function(){var a=$.namespace("pskl.drawingtools");a.Stroke=function(){this.toolId="tool-stroke",this.helpText="Stroke tool",this.startCol=null,this.startRow=null},pskl.utils.inherit(a.Stroke,a.BaseTool),a.Stroke.prototype.applyToolAt=function(a,b,c,d,e){this.startCol=a,this.startRow=b,e.setPixel(a,b,c)},a.Stroke.prototype.moveToolAt=function(a,b,c,d,e){e.clear();for(var f=this.getLinePixels_(this.startCol,a,this.startRow,b),g=0;gi;i++)for(var j=0;h>j;j++){var k=i-a,l=j-b;e.shiftKey&&(k=(k+g)%g,l=(l+h)%h),f=d.containsPixel(k,l)?d.getPixel(k,l):Constants.TRANSPARENT_COLOR,c.setPixel(i,j,f)}},a.Move.prototype.releaseToolAt=function(a,b,c,d,e,f){this.moveToolAt(a,b,c,d,e,f),this.raiseSaveStateEvent({colDiff:a-this.startCol,rowDiff:b-this.startRow,shiftKey:f.shiftKey})},a.Move.prototype.replay=function(a,b){var c={shiftKey:b.shiftKey};this.shiftFrame(b.colDiff,b.rowDiff,a,a.clone(),c)}}(),function(){var a=$.namespace("pskl.drawingtools");a.BaseSelect=function(){this.secondaryToolId=pskl.drawingtools.Move.TOOL_ID,this.BodyRoot=$("body"),this.startCol=null,this.startRow=null,this.selection=null,this.tooltipDescriptors=[{description:"Drag the selection to move it. You may switch to other layers and frames."},{key:"ctrl+c",description:"Copy the selected area"},{key:"ctrl+v",description:"Paste the copied area"}]},pskl.utils.inherit(a.BaseSelect,a.BaseTool),a.BaseSelect.prototype.applyToolAt=function(a,b,c,d,e){this.startCol=a,this.startRow=b,this.lastCol=a,this.lastRow=b,this.isInSelection(a,b)?(this.mode="moveSelection",this.onSelectionDragStart_(a,b,c,d,e)):(this.mode="select",this.onSelectStart_(a,b,c,d,e))},a.BaseSelect.prototype.moveToolAt=function(a,b,c,d,e){"select"==this.mode?this.onSelect_(a,b,c,d,e):"moveSelection"==this.mode&&this.onSelectionDrag_(a,b,c,d,e)},a.BaseSelect.prototype.releaseToolAt=function(a,b,c,d,e){"select"==this.mode?this.onSelectEnd_(a,b,c,d,e):"moveSelection"==this.mode&&this.onSelectionDragEnd_(a,b,c,d,e)},a.BaseSelect.prototype.moveUnactiveToolAt=function(a,b,c,d,e){e.containsPixel(a,b)&&(this.isInSelection(a,b)?(this.BodyRoot.addClass(this.secondaryToolId),this.BodyRoot.removeClass(this.toolId)):(this.BodyRoot.addClass(this.toolId),this.BodyRoot.removeClass(this.secondaryToolId)))},a.BaseSelect.prototype.isInSelection=function(a,b){return this.selection&&this.selection.pixels.some(function(c){return c.col===a&&c.row===b})},a.BaseSelect.prototype.hideHighlightedPixel=function(){},a.BaseSelect.prototype.drawSelectionOnOverlay_=function(a){for(var b=this.selection.pixels,c=0,d=b.length;d>c;c++){var e=b[c],f=e.color&&e.color!==Constants.TRANSPARENT_COLOR,g=f?this.getTransparentVariant(e.color):Constants.SELECTION_TRANSPARENT_COLOR;a.setPixel(b[c].col,b[c].row,g)}},a.BaseSelect.prototype.getTransparentVariant=function(a){var b=window.tinycolor(a);return b=window.tinycolor.lighten(b,10),b.setAlpha(.5),b.toRgbString()},a.BaseSelect.prototype.onSelectStart_=function(){},a.BaseSelect.prototype.onSelect_=function(){},a.BaseSelect.prototype.onSelectEnd_=function(){},a.BaseSelect.prototype.onSelectionDragStart_=function(){},a.BaseSelect.prototype.onSelectionDrag_=function(a,b,c,d,e){{var f=a-this.lastCol,g=b-this.lastRow; -a-this.startCol,b-this.startRow}this.selection.move(f,g),e.clear(),this.drawSelectionOnOverlay_(e),this.lastCol=a,this.lastRow=b},a.BaseSelect.prototype.onSelectionDragEnd_=function(a,b,c,d,e){this.onSelectionDrag_(a,b,c,d,e)}}(),function(){var a=$.namespace("pskl.drawingtools");a.RectangleSelect=function(){this.toolId="tool-rectangle-select",this.helpText="Rectangle selection",a.BaseSelect.call(this),this.hasSelection=!1},pskl.utils.inherit(a.RectangleSelect,a.BaseSelect),a.RectangleSelect.prototype.onSelectStart_=function(a,b,c,d,e){this.hasSelection?(this.hasSelection=!1,e.clear(),$.publish(Events.SELECTION_DISMISSED)):(this.hasSelection=!0,$.publish(Events.DRAG_START,[a,b]),e.setPixel(a,b,c))},a.RectangleSelect.prototype.onSelect_=function(a,b,c,d,e){this.hasSelection&&(e.clear(),this.selection=new pskl.selection.RectangularSelection(this.startCol,this.startRow,a,b),$.publish(Events.SELECTION_CREATED,[this.selection]),this.drawSelectionOnOverlay_(e))},a.RectangleSelect.prototype.onSelectEnd_=function(a,b,c,d,e){this.hasSelection&&(this.onSelect_(a,b,c,d,e),$.publish(Events.DRAG_END,[a,b]))}}(),function(){var a=$.namespace("pskl.drawingtools");a.ShapeSelect=function(){this.toolId="tool-shape-select",this.helpText="Shape selection",a.BaseSelect.call(this)},pskl.utils.inherit(a.ShapeSelect,a.BaseSelect),a.ShapeSelect.prototype.onSelectStart_=function(a,b,c,d,e){$.publish(Events.SELECTION_DISMISSED),e.clear();var f=pskl.PixelUtils.getSimilarConnectedPixelsFromFrame(d,a,b);this.selection=new pskl.selection.ShapeSelection(f),$.publish(Events.SELECTION_CREATED,[this.selection]),this.drawSelectionOnOverlay_(e)}}(),function(){var a=$.namespace("pskl.drawingtools");a.ColorPicker=function(){this.toolId="tool-colorpicker",this.helpText="Color picker"},pskl.utils.inherit(a.ColorPicker,a.BaseTool),a.ColorPicker.prototype.applyToolAt=function(a,b,c,d,e,f){if(d.containsPixel(a,b)){var g=d.getPixel(a,b);f.button==Constants.LEFT_BUTTON?$.publish(Events.SELECT_PRIMARY_COLOR,[g]):f.button==Constants.RIGHT_BUTTON&&$.publish(Events.SELECT_SECONDARY_COLOR,[g])}}}(),function(){var a=$.namespace("pskl.drawingtools");a.ColorSwap=function(){this.toolId="tool-colorswap",this.helpText="Paint all pixels of the same color",this.tooltipDescriptors=[{key:"ctrl",description:"Apply to all layers"},{key:"shift",description:"Apply to all frames"}]},pskl.utils.inherit(a.ColorSwap,a.BaseTool),a.ColorSwap.prototype.applyToolAt=function(a,b,c,d,e,f){if(d.containsPixel(a,b)){var g=d.getPixel(a,b),h=pskl.utils.UserAgent.isMac?f.metaKey:f.ctrlKey,i=f.shiftKey;this.swapColors(g,c,h,i),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})}},a.ColorSwap.prototype.swapColors=function(a,b,c,d){var e=function(c,d,e,f){c==a&&(f.pixels[d][e]=b)},f=pskl.app.piskelController.getCurrentLayer(),g=pskl.app.piskelController.getCurrentFrameIndex();pskl.app.piskelController.getPiskel().getLayers().forEach(function(a){(c||a===f)&&a.getFrames().forEach(function(a,b){(d||b===g)&&(a.forEachPixel(e),a.version++)})})}}(),function(){var a=$.namespace("pskl");a.app={init:function(){this.isAppEngineVersion=!!pskl.appEngineToken_,this.shortcutService=new pskl.service.keyboard.ShortcutService,this.shortcutService.init();var a={height:Constants.DEFAULT.HEIGHT,width:Constants.DEFAULT.WIDTH},b=new pskl.model.piskel.Descriptor("New Piskel",""),c=new pskl.model.Piskel(a.width,a.height,b),d=new pskl.model.Layer("Layer 1"),e=new pskl.model.Frame(a.width,a.height);d.addFrame(e),c.addLayer(d),this.corePiskelController=new pskl.controller.piskel.PiskelController(c),this.corePiskelController.init(),this.piskelController=new pskl.controller.piskel.PublicPiskelController(this.corePiskelController),this.piskelController.init(),this.paletteImportService=new pskl.service.palette.PaletteImportService,this.paletteService=new pskl.service.palette.PaletteService,this.paletteController=new pskl.controller.PaletteController,this.paletteController.init(),this.currentColorsService=new pskl.service.CurrentColorsService(this.piskelController),this.currentColorsService.init(),this.palettesListController=new pskl.controller.PalettesListController(this.paletteController,this.currentColorsService),this.palettesListController.init(),this.cursorCoordinatesController=new pskl.controller.CursorCoordinatesController(this.piskelController),this.cursorCoordinatesController.init(),this.drawingController=new pskl.controller.DrawingController(this.piskelController,this.paletteController,$("#drawing-canvas-container")),this.drawingController.init(),this.animationController=new pskl.controller.AnimatedPreviewController(this.piskelController,$("#animated-preview-canvas-container")),this.animationController.init(),this.minimapController=new pskl.controller.MinimapController(this.piskelController,this.animationController,this.drawingController,$("#animated-preview-canvas-container")),this.minimapController.init(),this.previewFilmController=new pskl.controller.PreviewFilmController(this.piskelController,$("#preview-list")),this.previewFilmController.init(),this.layersListController=new pskl.controller.LayersListController(this.piskelController),this.layersListController.init(),this.settingsController=new pskl.controller.settings.SettingsController(this.piskelController),this.settingsController.init(),this.dialogsController=new pskl.controller.dialogs.DialogsController(this.piskelController),this.dialogsController.init(),this.toolController=new pskl.controller.ToolController,this.toolController.init(),this.selectionManager=new pskl.selection.SelectionManager(this.piskelController),this.selectionManager.init(),this.historyService=new pskl.service.HistoryService(this.corePiskelController),this.historyService.init(),this.notificationController=new pskl.controller.NotificationController,this.notificationController.init(),this.canvasBackgroundController=new pskl.controller.CanvasBackgroundController,this.canvasBackgroundController.init(),this.localStorageService=new pskl.service.LocalStorageService(this.piskelController),this.localStorageService.init(),this.imageUploadService=new pskl.service.ImageUploadService,this.imageUploadService.init(),this.cheatsheetService=new pskl.service.keyboard.CheatsheetService,this.cheatsheetService.init(),this.savedStatusService=new pskl.service.SavedStatusService(this.piskelController),this.savedStatusService.init(),this.backupService=new pskl.service.BackupService(this.piskelController),this.backupService.init(),this.beforeUnloadService=new pskl.service.BeforeUnloadService(this.piskelController),this.beforeUnloadService.init(),this.fileDropperService=new pskl.service.FileDropperService(this.piskelController,$("#drawing-canvas-container").get(0)),this.fileDropperService.init(),this.storageService=this.isAppEngineVersion?new pskl.service.AppEngineStorageService(this.piskelController):new pskl.service.GithubStorageService(this.piskelController),this.storageService.init();var f=new pskl.rendering.DrawingLoop;f.addCallback(this.render,this),f.start(),this.initTooltips_();var g=this.getPiskelInitData_();g&&g.piskel&&this.loadPiskel_(g.piskel,g.descriptor,g.fps),pskl.devtools&&pskl.devtools.init()},loadPiskel_:function(a,b,c){pskl.utils.serialization.Deserializer.deserialize(a,function(a){a.setDescriptor(b),pskl.app.piskelController.setPiskel(a),pskl.app.animationController.setFPS(c)})},getPiskelInitData_:function(){return pskl.appEnginePiskelData_},isLoggedIn:function(){var a=this.getPiskelInitData_();return a&&a.isLoggedIn},initTooltips_:function(){$("body").tooltip({selector:"[rel=tooltip]"})},render:function(a){this.drawingController.render(a),this.animationController.render(a),this.previewFilmController.render(a)},getFirstFrameAsPng:function(){var a=this.piskelController.getFrameAt(0),b=new pskl.rendering.CanvasRenderer(a,1);b.drawTransparentAs("rgba(0,0,0,0)");var c=b.render();return c.toDataURL("image/png")},getFramesheetAsPng:function(){var a=new pskl.rendering.PiskelRenderer(this.piskelController),b=a.renderAsCanvas();return b.toDataURL("image/png")}}}(),function(){var a=function(a,b,c){var d=a.clone(),e=a.getWidth(),f=a.getHeight();d.forEachPixel(function(d,g,h){b&&(g=e-g-1),c&&(h=f-h-1),a.pixels[g][h]=d}),a.version++};window.flip=function(b,c){var d=pskl.app.piskelController.getCurrentFrameIndex(),e=pskl.app.piskelController.getLayers();e.forEach(function(e){a(e.getFrameAt(d),b,c)}),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})},window.copyToAll=function(){var a=pskl.app.piskelController.getCurrentFrame(),b=pskl.app.piskelController.getCurrentLayer();b.getFrames().forEach(function(b){b!==a&&b.setPixels(a.getPixels())}),$.publish(Events.PISKEL_RESET),$.publish(Events.PISKEL_SAVE_STATE,{type:pskl.service.HistoryService.SNAPSHOT})}}(); \ No newline at end of file diff --git a/palettes-proto/logo.png b/palettes-proto/logo.png deleted file mode 100644 index 8ee97465..00000000 Binary files a/palettes-proto/logo.png and /dev/null differ diff --git a/palettes-proto/piskel-boot-0.1.0.js b/palettes-proto/piskel-boot-0.1.0.js deleted file mode 100644 index 9777ac45..00000000 --- a/palettes-proto/piskel-boot-0.1.0.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2014-09-07-07-04 is replaced by the build version - */ - var version = '-2014-09-07-07-04'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/palettes-proto/piskelapp-partials/main-partial.html b/palettes-proto/piskelapp-partials/main-partial.html deleted file mode 100644 index bef8d7ee..00000000 --- a/palettes-proto/piskelapp-partials/main-partial.html +++ /dev/null @@ -1,48 +0,0 @@ - -
        - - -
        -
        - -
        - -
        -
        -
        -
        -
        - -
        - - - -
        -
        -
        - -
        -
        - -
        -
        - - - - - -
        -
        -
        -
        -
        - -
        -
        - - - -
        -
        - - diff --git a/palettes-proto/templates/cheatsheet.html b/palettes-proto/templates/cheatsheet.html deleted file mode 100644 index ee9203c8..00000000 --- a/palettes-proto/templates/cheatsheet.html +++ /dev/null @@ -1,24 +0,0 @@ - -Keyboard shortcuts - \ No newline at end of file diff --git a/palettes-proto/templates/dialogs/browse-local.html b/palettes-proto/templates/dialogs/browse-local.html deleted file mode 100644 index cd28bdad..00000000 --- a/palettes-proto/templates/dialogs/browse-local.html +++ /dev/null @@ -1,26 +0,0 @@ -
        -

        - Browse Local Piskels - X -

        -
        -
         
        - - - - - - - - -
        NameDateActions
        - - - \ No newline at end of file diff --git a/palettes-proto/templates/dialogs/create-palette.html b/palettes-proto/templates/dialogs/create-palette.html deleted file mode 100644 index 697e5430..00000000 --- a/palettes-proto/templates/dialogs/create-palette.html +++ /dev/null @@ -1,82 +0,0 @@ -
        -

        - Create palette - X -

        -
        -
        - Name - -
        - - -
        -
        -
        -
          -
          -
          -
          - H - - -
          -
          - S - - -
          -
          - V - - -
          -
          -
          - R - - -
          -
          - G - - -
          -
          - B - - -
          -
          -
          -
          -
          - - -
          -
          - - - - - -
          \ No newline at end of file diff --git a/palettes-proto/templates/dialogs/import-image.html b/palettes-proto/templates/dialogs/import-image.html deleted file mode 100644 index 95795799..00000000 --- a/palettes-proto/templates/dialogs/import-image.html +++ /dev/null @@ -1,27 +0,0 @@ -
          -

          - Import Image - X -

          -
          -
          -
          - Name : -
          -
          - Info : -
          -
          -
          - Size : - x - -
          -
          - Smooth resize : - -
          - -
          -
          -
          \ No newline at end of file diff --git a/palettes-proto/templates/drawing-tools.html b/palettes-proto/templates/drawing-tools.html deleted file mode 100644 index 623e7141..00000000 --- a/palettes-proto/templates/drawing-tools.html +++ /dev/null @@ -1,63 +0,0 @@ -
          -
          -
          -
            - -
          -
          -
          - -
          -
          - -
          -
          -
          -
          -
          - - - - - - - - - - - - - - -
          \ No newline at end of file diff --git a/palettes-proto/templates/frames-list.html b/palettes-proto/templates/frames-list.html deleted file mode 100644 index 5312ecfd..00000000 --- a/palettes-proto/templates/frames-list.html +++ /dev/null @@ -1,7 +0,0 @@ -
          -
          -
            -
            -
            -
            -
            \ No newline at end of file diff --git a/palettes-proto/templates/layers-list.html b/palettes-proto/templates/layers-list.html deleted file mode 100644 index 7208e10d..00000000 --- a/palettes-proto/templates/layers-list.html +++ /dev/null @@ -1,20 +0,0 @@ -
            -

            Layers -
            -

            -
            - - - - -
            - -
              -
              diff --git a/palettes-proto/templates/palettes-list.html b/palettes-proto/templates/palettes-list.html deleted file mode 100644 index f103c8eb..00000000 --- a/palettes-proto/templates/palettes-list.html +++ /dev/null @@ -1,37 +0,0 @@ -
              -

              - Palettes -
              +
              -

              -
              - -
              dl
              -
              d
              -
              e
              -
              -
              - -
              - - diff --git a/palettes-proto/templates/preview.html b/palettes-proto/templates/preview.html deleted file mode 100644 index d7129d62..00000000 --- a/palettes-proto/templates/preview.html +++ /dev/null @@ -1,13 +0,0 @@ -
              -
              -
              -
              -
              -
              - - -
              -
              \ No newline at end of file diff --git a/palettes-proto/templates/settings.html b/palettes-proto/templates/settings.html deleted file mode 100644 index c8d61934..00000000 --- a/palettes-proto/templates/settings.html +++ /dev/null @@ -1,37 +0,0 @@ -
              -
              -
              - -
              -
              - -
              -
              - -
              -
              - -
              -
              - -
              \ No newline at end of file diff --git a/palettes-proto/templates/settings/application.html b/palettes-proto/templates/settings/application.html deleted file mode 100644 index 22c72076..00000000 --- a/palettes-proto/templates/settings/application.html +++ /dev/null @@ -1,38 +0,0 @@ -
              -
              - Canvas settings: -
              -
              - -
              -
              -
              -
              -
              -
              -
              -
              -
              -
              -
              -
              - - -
              - - -
              - diff --git a/palettes-proto/templates/settings/export.html b/palettes-proto/templates/settings/export.html deleted file mode 100644 index 56865939..00000000 --- a/palettes-proto/templates/settings/export.html +++ /dev/null @@ -1,46 +0,0 @@ -
              -
              - Export Spritesheet -
              -
              -
              - PNG with all frames side by side. - -
              -
              - Export as ZIP -
              -
              - ZIP with one PNG file per frame. - File names will start with the prefix below. -
              - - -
              - -
              -
              - Export to Animated GIF -
              -
              -
              -
              - - - -
              -
              - - -
              -
              -
              -
              -
              -
              - -
              -
              -
              diff --git a/palettes-proto/templates/settings/import.html b/palettes-proto/templates/settings/import.html deleted file mode 100644 index 733aee4b..00000000 --- a/palettes-proto/templates/settings/import.html +++ /dev/null @@ -1,55 +0,0 @@ -
              -
              - Load from Browser -
              -
              - Load a local piskel saved in this Browser -
              - -
              -
              -
              - Load .piskel file -
              -
              - Load a .piskel file from your computer - -
              - - - -
              -
              -
              - Import From Picture -
              -
              -
              Supports : PNG, JPG, BMP, Animated GIF ...
              -
              - - -
              -
              -
              - Recover recent sessions -
              -
              - -
              - - -
              \ No newline at end of file diff --git a/palettes-proto/templates/settings/resize.html b/palettes-proto/templates/settings/resize.html deleted file mode 100644 index bc8040ff..00000000 --- a/palettes-proto/templates/settings/resize.html +++ /dev/null @@ -1,20 +0,0 @@ -
              -
              - Resize drawing area -
              -
              -
              -
              - Size : - x - -
              -
              - Resize canvas content : - -
              - - -
              -
              -
              \ No newline at end of file diff --git a/palettes-proto/templates/settings/save.html b/palettes-proto/templates/settings/save.html deleted file mode 100644 index 1dbc9821..00000000 --- a/palettes-proto/templates/settings/save.html +++ /dev/null @@ -1,46 +0,0 @@ -
              -
              -
              Describe your piskel
              -
              -
              - - -
              -
              - -
              -
              - -
              -
              -
              Save online
              -
              - -
              -
              -
              Save offline in Browser
              -
              - -
              Your piskel will be saved locally and will only be accessible from this browser.
              -
              -
              Save offline as File
              -
              - -
              -
              -
              - - - - - - -
              \ No newline at end of file diff --git a/piskel-boot-0.1.0.js b/piskel-boot-0.1.0.js deleted file mode 100644 index 87807ff6..00000000 --- a/piskel-boot-0.1.0.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2014-07-14-04-44 is replaced by the build version - */ - var version = '-2014-07-14-04-44'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-02-19-01-09.js b/piskel-boot-2015-02-19-01-09.js deleted file mode 100644 index 7c841836..00000000 --- a/piskel-boot-2015-02-19-01-09.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-02-19-01-09 is replaced by the build version - */ - var version = '-2015-02-19-01-09'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-03-02-09-38.js b/piskel-boot-2015-03-02-09-38.js deleted file mode 100644 index edb2b9ae..00000000 --- a/piskel-boot-2015-03-02-09-38.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-03-02-09-38 is replaced by the build version - */ - var version = '-2015-03-02-09-38'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-03-02-09-41.js b/piskel-boot-2015-03-02-09-41.js deleted file mode 100644 index eb9b16fe..00000000 --- a/piskel-boot-2015-03-02-09-41.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-03-02-09-41 is replaced by the build version - */ - var version = '-2015-03-02-09-41'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-03-02-09-45.js b/piskel-boot-2015-03-02-09-45.js deleted file mode 100644 index 362cadbc..00000000 --- a/piskel-boot-2015-03-02-09-45.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-03-02-09-45 is replaced by the build version - */ - var version = '-2015-03-02-09-45'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-04-27-12-01.js b/piskel-boot-2015-04-27-12-01.js deleted file mode 100644 index 7982324f..00000000 --- a/piskel-boot-2015-04-27-12-01.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-04-27-12-01 is replaced by the build version - */ - var version = '-2015-04-27-12-01'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot-2015-09-14-10-01.js b/piskel-boot-2015-09-14-10-01.js deleted file mode 100644 index 41f14706..00000000 --- a/piskel-boot-2015-09-14-10-01.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-09-14-10-01 is replaced by the build version - */ - var version = '-2015-09-14-10-01'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskel-boot.js b/piskel-boot.js deleted file mode 100644 index 41f14706..00000000 --- a/piskel-boot.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - - /** - * See @Gruntfile.js => after build, -2015-09-14-10-01 is replaced by the build version - */ - var version = '-2015-09-14-10-01'; - var versionHasNotBeenReplaced = version.indexOf('@@') === 0; - if (versionHasNotBeenReplaced) { - version = ''; - } - - window.onPiskelReady = function () { - var loadingMask = document.getElementById('loading-mask'); - loadingMask.style.opacity = 0; - window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600); - pskl.app.init(); - // cleanup - delete window.pskl_exports; - delete window.loadDebugScripts; - delete window.done; - }; - - var prefixPath = function (path) { - if (window.pskl && window.pskl.appEngineToken_) { - return '../' + path; - } else { - return path; - } - }; - - var loadScript = function (src, callback) { - src = prefixPath(src); - var script = window.document.createElement('script'); - script.setAttribute('src',src); - script.setAttribute('onload',callback); - window.document.body.appendChild(script); - }; - - var loadStyle = function (src) { - src = prefixPath(src); - var link = document.createElement('link'); - link.setAttribute('href', src); - link.setAttribute('rel', 'stylesheet'); - link.setAttribute('type', 'text/css'); - document.head.appendChild(link); - }; - - if (window.location.href.indexOf('debug') != -1) { - window.pskl_exports = {}; - var scriptIndex = 0; - window.loadNextScript = function () { - if (scriptIndex == window.pskl_exports.scripts.length) { - window.onPiskelReady(); - } else { - loadScript(window.pskl_exports.scripts[scriptIndex], 'loadNextScript()'); - scriptIndex ++; - } - }; - loadScript('piskel-script-list.js', 'loadNextScript()'); - - window.loadStyles = function () { - var styles = window.pskl_exports.styles; - for (var i = 0 ; i < styles.length ; i++) { - loadStyle(styles[i]); - } - }; - loadScript('piskel-style-list.js', 'loadStyles()'); - } else { - var script; - if (window.location.href.indexOf('pack') != -1) { - script = 'js/piskel-packaged' + version + '.js'; - } else { - script = 'js/piskel-packaged-min' + version + '.js'; - } - loadStyle('css/piskel-style-packaged' + version + '.css'); - - var loaderInterval = window.setInterval(function () { - if (document.querySelectorAll('[data-iframe-loader]').length === 0) { - window.clearInterval(loaderInterval); - loadScript(script, 'onPiskelReady()'); - } else { - window.console.log('waiting for templates to load ....'); - } - }, 100); - } -})(); \ No newline at end of file diff --git a/piskelapp-partials/main-partial.html b/piskelapp-partials/main-partial.html index d809593b..b0ec9f87 100644 --- a/piskelapp-partials/main-partial.html +++ b/piskelapp-partials/main-partial.html @@ -1,10 +1,61 @@ - +{% raw %}
              - +
              +
              +
              +
              +
              +
              +
              +
              +
              +
                + +
              +
              +
              + +
              +
              + +
              +
              +
              +
              +
              + + + + + +
              - +
              +
              +
                +
                +
                +
                +
                @@ -14,24 +65,145 @@
                - - - - +
                +
                +
                +
                1x
                +
                +
                + +
                +
                +
                +
                +
                +
                + + +
                +
                +
                +
                +
                +

                Layers +
                +

                +
                + + + + + + + + + + + + +
                + +
                  + + +
                  + +
                  +

                  Transform

                  +
                    +
                    +
                    +

                    Palettes

                    +
                    + + + +
                    +
                    + + + + +
                    + + +
                    - +
                    +
                    +
                    + +
                    +
                    + +
                    +
                    + +
                    +
                    + +
                    +
                    + +
                    - - - - -
                    @@ -40,14 +212,724 @@
                    - - -
                    - - - +
                    + - + + + + + + + + +
                    +
                    + +
                    + +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% endraw %} \ No newline at end of file diff --git a/popup-preview.html b/popup-preview.html deleted file mode 100644 index 517f5d85..00000000 --- a/popup-preview.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - Preview - - - - - - \ No newline at end of file diff --git a/templates/cheatsheet.html b/templates/cheatsheet.html deleted file mode 100644 index d4fbdb03..00000000 --- a/templates/cheatsheet.html +++ /dev/null @@ -1,28 +0,0 @@ - -  - \ No newline at end of file diff --git a/templates/dialogs/browse-local.html b/templates/dialogs/browse-local.html deleted file mode 100644 index cd28bdad..00000000 --- a/templates/dialogs/browse-local.html +++ /dev/null @@ -1,26 +0,0 @@ -
                    -

                    - Browse Local Piskels - X -

                    -
                    - - - - - - - - - -
                    NameDateActions
                    -
                    - -
                    \ No newline at end of file diff --git a/templates/dialogs/create-palette.html b/templates/dialogs/create-palette.html deleted file mode 100644 index 1df6f597..00000000 --- a/templates/dialogs/create-palette.html +++ /dev/null @@ -1,83 +0,0 @@ -
                    -

                    - Create palette - X -

                    -
                    -
                    - Name - -
                    - - - -
                    -
                    -
                    -
                      -
                      -
                      -
                      - -
                      -
                      - H - - -
                      -
                      - S - - -
                      -
                      - V - - -
                      -
                      -
                      - R - - -
                      -
                      - G - - -
                      -
                      - B - - -
                      -
                      -
                      -
                      -
                      - - - - -
                      -
                      - - - -
                      \ No newline at end of file diff --git a/templates/dialogs/import-image.html b/templates/dialogs/import-image.html deleted file mode 100644 index f37e95cb..00000000 --- a/templates/dialogs/import-image.html +++ /dev/null @@ -1,49 +0,0 @@ -
                      -

                      - Import Image - X -

                      -
                      -
                      -
                      - Name : -
                      -
                      -
                      Preview :
                      -
                      -
                      -
                      - -
                      -
                      - Resize to - x - -
                      -
                      - Smooth resize - -
                      -
                      - -
                      -
                      - Frame size - x - -
                      -
                      - Offset - x - -
                      - -
                      -
                      -
                      \ No newline at end of file diff --git a/templates/dialogs/manage-palettes.html b/templates/dialogs/manage-palettes.html deleted file mode 100644 index 795cbcaa..00000000 --- a/templates/dialogs/manage-palettes.html +++ /dev/null @@ -1,57 +0,0 @@ -
                      -

                      - Palette manager - X -

                      -
                      -
                      -
                      - - -
                      -
                        -
                      -
                      -
                      -
                      -
                      -
                      -
                      -
                      - - - - - - \ No newline at end of file diff --git a/templates/drawing-tools.html b/templates/drawing-tools.html deleted file mode 100644 index 08f4bbac..00000000 --- a/templates/drawing-tools.html +++ /dev/null @@ -1,63 +0,0 @@ -
                      -
                      -
                      -
                        - -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -
                      -
                      - - - - - - - - - - - - - - -
                      \ No newline at end of file diff --git a/templates/frames-list.html b/templates/frames-list.html deleted file mode 100644 index 5312ecfd..00000000 --- a/templates/frames-list.html +++ /dev/null @@ -1,7 +0,0 @@ -
                      -
                      -
                        -
                        -
                        -
                        -
                        \ No newline at end of file diff --git a/templates/layers-list.html b/templates/layers-list.html deleted file mode 100644 index 48f28f3b..00000000 --- a/templates/layers-list.html +++ /dev/null @@ -1,40 +0,0 @@ -
                        -

                        Layers -
                        -

                        -
                        - - - - - - - - - - - - -
                        - -
                          - - -
                          diff --git a/templates/misc-templates.html b/templates/misc-templates.html deleted file mode 100644 index 56d5a0b7..00000000 --- a/templates/misc-templates.html +++ /dev/null @@ -1,9 +0,0 @@ -
                          - -
                          \ No newline at end of file diff --git a/templates/palettes-list.html b/templates/palettes-list.html deleted file mode 100644 index ef7824b1..00000000 --- a/templates/palettes-list.html +++ /dev/null @@ -1,27 +0,0 @@ -
                          -

                          Palettes

                          -
                          - - - -
                          -
                          - - - - -
                          - - diff --git a/templates/popup-preview.html b/templates/popup-preview.html deleted file mode 100644 index 4996cec6..00000000 --- a/templates/popup-preview.html +++ /dev/null @@ -1,64 +0,0 @@ -
                          - -
                          \ No newline at end of file diff --git a/templates/preview.html b/templates/preview.html deleted file mode 100644 index 468a6054..00000000 --- a/templates/preview.html +++ /dev/null @@ -1,22 +0,0 @@ -
                          -
                          -
                          -
                          1x
                          -
                          -
                          - -
                          -
                          -
                          -
                          -
                          -
                          - - -
                          -
                          -
                          -
                          \ No newline at end of file diff --git a/templates/settings.html b/templates/settings.html deleted file mode 100644 index c8d61934..00000000 --- a/templates/settings.html +++ /dev/null @@ -1,37 +0,0 @@ -
                          -
                          -
                          - -
                          -
                          - -
                          -
                          - -
                          -
                          - -
                          -
                          - -
                          \ No newline at end of file diff --git a/templates/settings/application.html b/templates/settings/application.html deleted file mode 100644 index af487ff1..00000000 --- a/templates/settings/application.html +++ /dev/null @@ -1,63 +0,0 @@ -
                          -
                          -
                          - General -
                          -
                          - -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          - -
                          - - -
                          - -
                          - - - -
                          - -
                          - -
                          -
                          - Preview -
                          - -
                          - -
                          - -
                          - - -
                          - - -
                          -
                          - diff --git a/templates/settings/export.html b/templates/settings/export.html deleted file mode 100644 index 6163fd28..00000000 --- a/templates/settings/export.html +++ /dev/null @@ -1,55 +0,0 @@ -
                          -
                          - Export Spritesheet -
                          -
                          - PNG with all frames side by side. - -
                          -
                          - Export as ZIP -
                          -
                          - ZIP with one PNG file per frame. - File names will start with the prefix below. -
                          - - -
                          -
                          - -
                          - -
                          -
                          - Export to Animated GIF -
                          -
                          -
                          -
                          - -
                          - Width - - px -
                          -
                          - Height - - px -
                          -
                          -
                          - - -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          diff --git a/templates/settings/import.html b/templates/settings/import.html deleted file mode 100644 index 0508d22e..00000000 --- a/templates/settings/import.html +++ /dev/null @@ -1,55 +0,0 @@ -
                          -
                          - Load from Browser -
                          -
                          - Load a local piskel saved in this Browser -
                          - -
                          -
                          -
                          - Load .piskel file -
                          -
                          - Load a .piskel file from your computer - -
                          - - - -
                          -
                          -
                          - Import From Picture -
                          -
                          -
                          Supports PNG, JPG, BMP, Animated GIF
                          -
                          - - -
                          -
                          -
                          - Recover recent sessions -
                          -
                          - -
                          - - -
                          \ No newline at end of file diff --git a/templates/settings/resize.html b/templates/settings/resize.html deleted file mode 100644 index f321111b..00000000 --- a/templates/settings/resize.html +++ /dev/null @@ -1,66 +0,0 @@ -
                          - -
                          - Resize -
                          -
                          -
                          -
                          - Width - - px -
                          -
                          - Height - - px -
                          -
                          - -
                          -
                          - -
                          -
                          - Anchor -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          -
                          - -
                          -
                          - -
                          - Default size -
                          -
                          -
                          -
                          - Width - - px -
                          -
                          - Height - - px -
                          - -
                          -
                          -
                          \ No newline at end of file diff --git a/templates/settings/save.html b/templates/settings/save.html deleted file mode 100644 index 21f0eb23..00000000 --- a/templates/settings/save.html +++ /dev/null @@ -1,76 +0,0 @@ -
                          -
                          -
                          Describe your piskel
                          -
                          -
                          - - -
                          -
                          - - -
                          -
                          - -
                          -
                          -
                          - - - - - - - - - - - - - - - - - - - - - -
                          diff --git a/templates/transformations.html b/templates/transformations.html deleted file mode 100644 index 36e77e45..00000000 --- a/templates/transformations.html +++ /dev/null @@ -1,4 +0,0 @@ -
                          -

                          Transform

                          -
                            -
                            \ No newline at end of file