Repository: mrflix/LayerStyles Branch: master Commit: 0f8679a39ce7 Files: 23 Total size: 199.2 KB Directory structure: gitextract_kja_9fna/ ├── .project ├── README.markdown ├── builder.html ├── css/ │ ├── index.css │ └── style.css ├── index.html └── js/ ├── application.js ├── codebox.js ├── color.js ├── colorpicker.js ├── css.js ├── gradienteditor.js ├── localization.js ├── numbers.js ├── style.js ├── styleStore.js ├── tools.js ├── ui.js ├── universe.js └── zeroclipboard/ ├── ZeroClipboard.as ├── ZeroClipboard.fla ├── ZeroClipboard.js └── ZeroClipboard.swf ================================================ FILE CONTENTS ================================================ ================================================ FILE: .project ================================================ LayerStyles ================================================ FILE: README.markdown ================================================ Layer Styles ============ A HTML5 app for creating CSS3 in a intuitive way. Highlights ---------- - Colorpicker can pick any color of the element your working on - Drag and Drop images onto the page to use them as a background or to pick their colors - Color Swatches, Gradients and Styles are locally stored ================================================ FILE: builder.html ================================================ Layer Styles
CSS Code
copy
rgbhex

Layer Style

Styles

Drop Shadow

%
°
px
px
px

Inner Shadow

%
°
px
px
px

Background

%
°

Border

%
px

Border Radius

px%

Gradient Editor

Presets

Name:

Gradient

Stops

Color:
%

Colorpicker

  • °
  • %
  • %
================================================ FILE: css/index.css ================================================ * { margin: 0; padding: 0; } html { height: 100%; } body { font: 12px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; background-color: #fcfcfc; background-image: -moz-linear-gradient(top, rgba(52,154,227,0.21), rgba(52,154,227,0) 13px); background-image: -webkit-linear-gradient(top, rgba(52,154,227,0.21), rgba(52,154,227,0) 13px); background-image: -o-linear-gradient(top, rgba(52,154,227,0.21), rgba(52,154,227,0) 13px); background-image: -ms-linear-gradient(top, rgba(52,154,227,0.21), rgba(52,154,227,0) 13px); } #arche { padding-top: 55px; width: 556px; margin: 0 auto; text-transform: uppercase; text-shadow: 0 1px white; z-index: 200; position: relative; -moz-transition: 320ms; -webkit-transition: 320ms; transition: 320ms; } h1 span { color: #349ae3; text-transform: none; font-size: 16px; } h3 { color: #666; font-weight: normal; } a { text-decoration: none; color: #349ae3; } em { font-weight: bold; font-style: normal; } img { border: none; } #header { margin-top: 14px; padding-left: 100px; position: relative; background: url(../img/logo.png) no-repeat 24px 5px; } .hero { top: 0; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; -moz-box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); -webkit-box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); position: relative; } #ready { margin: 17px 0 21px; display: none; } #ready .hero { -moz-transition: 240ms ease; -webkit-transition: 240ms ease; transition: 240ms ease; } #ready:hover .hero { top: 3px; -moz-box-shadow: 0 12px 40px 8px rgba(0,0,0,.20), 0 0 0 1px rgba(0,0,0,.16); -webkit-box-shadow: 0 12px 40px 8px rgba(0,0,0,.20), 0 0 0 1px rgba(0,0,0,.16); box-shadow: 0 12px 40px 8px rgba(0,0,0,.20), 0 0 0 1px rgba(0,0,0,.16); } #not-ready { margin: 17px 0 21px; display: none; position: relative; } #not-ready .holder { left: 153px; top: 76px; width: 276px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.21), 0 15px 40px 10px rgba(0, 0, 0, 0.34); -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.21), 0 15px 40px 10px rgba(0, 0, 0, 0.34); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.21), 0 15px 40px 10px rgba(0, 0, 0, 0.34); position: absolute; text-shadow: none; text-transform: none; } #not-ready .upper { padding: 13px; border: 1px solid #A6281C; background: #F03432; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; -moz-box-shadow: 0 0 0 1px #F25146 inset; -webkit-box-shadow: 0 0 0 1px #F25146 inset; box-shadow: 0 0 0 1px #F25146 inset; } #not-ready h2 { padding-bottom: 13px; font-size: 14px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.21); border-bottom: 1px solid rgba(0, 0, 0, 0.34); } .features { border-top: 1px solid rgba(255,255,255,.13); padding-top: 8px; line-height: 2; } .features span { display: none; padding: 1px 8px; color: white; white-space: nowrap; background: #F25146; text-shadow: 0 1px 0 rgba(255,255,255,0.21); -moz-border-radius: 7px; -webkit-border-radius: 7px; border-radius: 7px; } #not-ready .bottom { padding: 13px; color: white; text-shadow: 0 2px black; background: black; background: rgba(0,0,0,.8); -webkit-border-bottom-left-radius: 4px; -webkit-border-bottom-right-radius: 4px; -moz-border-radius-bottomleft: 4px; -moz-border-radius-bottomright: 4px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } .js.nativejson.flexbox.canvas.rgba.borderradius.boxshadow.cssgradients #ready { display: block; } .no-js #not-ready, .no-flexbox #not-ready, .no-canvas #not-ready, .no-rgba #not-ready, .no-borderradius #not-ready, .no-boxshadow #not-ready, .no-cssgradients #not-ready { display: block; } .no-js .feature-js { display: inline; } .no-nativejson .feature-json { display: inline; } .no-flexbox .feature-flexbox { display: inline; } .no-canvas .feature-canvas { display: inline; } .no-rgba .feature-rgba { display: inline; } .no-borderradius .feature-borderradius { display: inline; } .no-boxshadow .feature-boxshadow { display: inline; } .no-cssgradients .feature-cssgradients { display: inline; } footer { padding: 0 21px; color: rgba(0,0,0,.34); } ================================================ FILE: css/style.css ================================================ * { margin: 0; padding: 0; } body, html { height: 100%; overflow: hidden; } body { width: 100%; font: 12px/14px "Helvetica Neue", Helvetica, Arial, sans-serif; background: url(../img/transparent.gif); } .box { display: -moz-box; display: -webkit-box; display: box; } .box.vertical { -moz-box-orient: vertical; -webkit-box-orient: vertical; box-orient: vertical; } .flex { -webkit-box-flex: 1; -moz-box-flex: 1; box-flex: 1; } ul { list-style: none; } #helper { top: 5px; right: 5px; padding: 8px 13px; position: absolute; z-index: 9999; background: rgba(0,0,0,.5); -moz-border-radius: 13px; -webkit-border-radius: 13px; border-radius: 13px; } #layer { top: 50%; left: 50%; margin: -150px 0 0 -150px; width: 300px; height: 300px; position: absolute; z-index: 99; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; opacity: 1; } #resize { bottom: -15px; right: -15px; width: 30px; height: 30px; position: absolute; } #layer.borderRadius:hover #resize { border-right: 1px solid rgba(0, 0, 0, 0.1); border-bottom: 1px solid rgba(0, 0, 0, 0.1); } #main { position: relative; height: 100%; width: 100%; } #workspace { position: relative; } #parallel_universe { position: absolute; z-index: -1; } #innerShadow_universe { position: absolute; z-index: -1; } #background_layer { background: -moz-linear-gradient(top, #e2e2e2, #ababab); background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#ababab)); background: -o-linear-gradient(top, #e2e2e2, #ababab); display: block; } #codeBoxToggle { bottom: 0; left: 0; padding: 5px 13px 4px; line-height: 18px; color: rgba(0, 0, 0, 0.75); background: rgba(0,0,0,.08); border-radius: 2px 2px 0 0; position: absolute; cursor: pointer; display: inline-block; z-index: 101; -moz-transition: background-color 240ms ease; -webkit-transition: background-color 240ms ease; transition: background-color 240ms ease; } #codeBoxToggle:hover { background: rgba(0,0,0,.13); } #overlay { width: 100%; height: 100%; position: absolute; top: 0; background-color: transparent; -moz-transition: background-color 240ms ease; -webkit-transition: background-color 240ms ease; transition: background-color 240ms ease; } .dragging #overlay { z-index: 101; background-color: rgba(0,0,0,.21); } .pick #overlay { z-index: 100; cursor: url(../img/eyedropper.gif) 0 15, auto; } #infoButton { position: absolute; left: 0; padding: 13px; color: black; text-decoration: none; text-transform: uppercase; opacity: 0.21; z-index: 99; display: block; -moz-transition: 240ms; -webkit-transition: 240ms; transition: 240ms; } #infoButton:hover { opacity: 0.55; } #codeBox { height: 0; position: relative; overflow: hidden; background-position: 0 2px; -webkit-transition: 300ms ease-out; -moz-transition: 300ms ease-out; transition: 300ms ease-out; } #codeBox.resizing { -webkit-transition: none; -moz-transition: none; transition: none; } #codeBox .dragger.y { top: 0; height: 21px; background: -moz-linear-gradient(#9E9E9E, #999); background: -webkit-gradient(linear, center top, center bottom, from(#9E9E9E), to(#999)); background: -webkit-linear-gradient(#9E9E9E, #99); border-bottom: 1px solid #666; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; display: block; position: relative; z-index: 1; } #copyCode { top: 21px; left: 1px; width: 78px; height: 15px; color: #444; font-family: "Consolas", "Monaco", monospace; line-height: 15px; font-size: 10px; text-align: center; border: 1px solid #edc59c; border-radius: 4px; background-image: -moz-repeating-linear-gradient(-45deg, transparent, transparent 2px, #edc59c 2px, #edc59c 3px); background-image: -webkit-repeating-linear-gradient(-45deg, transparent, transparent 2px, #edc59c 2px, #edc59c 3px); background-size: 4px 4px; position: absolute; cursor: pointer; } #copyCode:active { color: black; } #copyCode embed { left: 0; position: absolute; outline: none; } #colorSwitch { top: 41px; left: 1px; width: 78px; height: 15px; color: #444; border: 1px solid #edc59c; border-radius: 4px; overflow: hidden; position: absolute; } .toggle { cursor: pointer; } #colorSwitch .slidePanel { width: 150%; height: 100%; left: -50%; margin: 1px; position: absolute; -moz-transition: 320ms ease; -webkit-transition: 320ms ease; } #colorSwitch.moving .slidePanel { -moz-transition: none; -webkit-transition: none; } #colorSwitch .button { top: 0; left: 33.33%; width: 35px; height: 11px; position: absolute; border: 1px solid #edc59c; border-radius: 3px; background-image: -moz-repeating-linear-gradient(-45deg, transparent, transparent 2px, #edc59c 2px, #edc59c 3px); background-image: -webkit-repeating-linear-gradient(-45deg, transparent, transparent 2px, #edc59c 2px, #edc59c 3px); background-size: 4px 4px; } #colorSwitch .left, #colorSwitch .right { right: 0; width: 33.33%; height: 100%; line-height: 13px; font-size: 10px; text-align: center; position: absolute; } #colorSwitch .left { left: 0; right: auto; } #codeBox .body { color: #444; height: 100%; border-top: 1px solid rgba(0,0,0,.13); overflow: auto; position: relative; } .paper { background-color: #ffe4b5; /* lines */ background-image: -moz-linear-gradient(left, transparent 82px, rgba(128,0,0,.08) 82px, rgba(128,0,0,.08) 82px, transparent 83px), -moz-repeating-linear-gradient(transparent, transparent 19px, rgba(128, 0, 0, 0.08) 19px, rgba(128, 0, 0, 0.08) 20px); background-image: -webkit-linear-gradient(left, transparent 82px, rgba(128,0,0,.08) 82px, rgba(128,0,0,.08) 82px, transparent 83px), -webkit-repeating-linear-gradient(transparent, transparent 19px, rgba(128, 0, 0, 0.08) 19px, rgba(128, 0, 0, 0.08) 20px); } #codeBox .scroll { padding: 20px 0 0 108px; } #codeBox code { padding-bottom: 20px; border: none; font-family: "Consolas", monospace; line-height: 20px; display: block; } .dragger { position: absolute; z-index: 100; } .dragger.x { width: 10px; left: -5px; top: 0; height: 100%; cursor: w-resize; } .dragger.y { width: 100%; top: -5px; left: 0; height: 10px; cursor: n-resize; } .dragBox { bottom: 0; left: 5px; height: 20px; width: 20px; border: 1px solid rgba(0,0,0,.13); background: url(../img/dragger.png) no-repeat 6px 6px; position: absolute; } .dragger.y .dragBox { bottom: -1px; border: none; -moz-transform: rotate(90deg); -webkit-transform: rotate(90deg); transform: rotate(90deg); -moz-transform-origin: center center; -webkit-transform-origin: center center; transform-origin: center center; } .moveable { cursor: move; } #layerstyle { top: 11px; left: 51px; width: 556px; height: 393px; color: black; background: #EDEDED; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; -moz-box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); -webkit-box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); box-shadow: 0 15px 40px 10px rgba(0,0,0,.25), 0 0 0 1px rgba(0,0,0,.16); position: absolute; z-index: 100; display: block; -webkit-user-select: none; -moz-user-select: none; -o-user-select: none; user-select: none; } #headerBg { top: 0; left: 0; width: 100%; height: 24px; border-top: 1px solid #E2E2E2; border-bottom: 1px solid #515151; background: -moz-linear-gradient(#CFCFCF, #A8A8A8); background: -webkit-gradient(linear, center top, center bottom, from(#CFCFCF), to(#A8A8A8)); -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; position: absolute; } .window { top: 0; width: 100%; position: absolute; } .window .head { padding: 6px; position: relative; } .window .head h2 { font-size: 13px; font-weight: normal; text-align: center; color: black; text-shadow: 0 1px 0 #cfcfcf; } .window .head > button { position: absolute; left: 3px; top: 3px; width: auto; padding: 1px 9px; text-shadow: 0 1px 0 white; background: -moz-linear-gradient(top, #ebebeb, #d7d7d7); background: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#d7d7d7)); border: 1px solid #999999; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.5), 0 1px 0 white inset; -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.5), 0 1px 0 white inset; box-shadow: 0 1px 0 rgba(255,255,255,0.5), 0 1px 0 white inset; cursor: pointer; } .window .body { padding: 15px 10px; position: relative; } .inactive { color: gray; } #dialog { visibility: hidden; } .main { width: 82%; float: left; font-size: 10px; } .main > .styles { width: 72%; float: left; } #holder { margin: 0 16px; } #holder > div { width: 100%; visibility: hidden; position: absolute; top: 0; padding: 12px 0; border: 1px solid #909090; } #holder > div.active { visibility: visible; } .holder { position: relative; } .holder h3 { left: 9px; top: -8px; padding: 0 3px 0 2px; font-size: 10px; position: absolute; background: #ededed; } .styles > div > div > label { width: 22%; padding-top: 1px; margin-right: 2%; text-align: right; float: left; clear: right; } .styles label + div { width: 75%; float: right; } .styles label, .styles label + div { margin-top: 2px; } .styles .color_field { height: 13px; width: 33px; border: 1px solid #909090; background: white; cursor: pointer; } .styles input[type=checkbox] { margin: 0 6px; vertical-align: middle; width: auto; } .styles input[type=checkbox] + label { vertical-align: middle; } .styles .angle_holder { top: 13px; position: relative; display: inline-block; vertical-align: top; } input[type=text] { width: 40px; padding: 1px; font-size: 10px; border: 1px solid #909090; border-bottom-width: 0; -moz-box-shadow: inset 0 0 0 1px #bababa, 0 1px 0 rgba(0,0,0,.04); -webkit-box-shadow: inset 0 0 0 1px #bababa, 0 1px 0 rgba(0,0,0,.04); box-shadow: inset 0 0 0 1px #bababa, 0 1px 0 rgba(0,0,0,.04); } .styles .slider { width: 100px; margin: 0 5px 0 3px; } #stylePresets { margin: -2px 9px 0; height: 230px; overflow: auto; } #stylePresets .swatch { width: 31px; height: 31px; border-right: 1px solid #909090; border-bottom: 1px solid #909090; float: left; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } #stylePresets .swatch.active { border: 2px solid black; } #stylePresets .swatch > div { width: 17px; height: 17px; margin: 7px 0 0 7px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } #stylePresets .swatch.active > div { margin: 5px 0 0 5px; } #holder #background { } .gradientField { margin: 2px 0; width: 109px; height: 15px; vertical-align: middle; border: 1px solid black; display: inline-block; cursor: pointer; } .previews > div { margin: 2px 2px 2px 0; width: 24px; height: 24px; border: 1px solid black; display: inline-block; opacity: 0.3; } .previews > .active { opacity: 1; background-color: #A7D4F6; } .inactive .previews > .active { background-color: rgba(0,0,0,.08); border-color: gray; } #border .previews > div { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } #border_style_dotted { border-style: dotted; } #border_style_dashed { border-style: dashed; } #border_style_double { border: 3px double black; } #border_radius_preview { width: 104px; height: 104px; margin: 4px 3px; float: left; border-color: rgba(0,0,0,.25); position: relative; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; overflow: hidden; } #border_radius_preview > div { width: 50%; height: 50%; float: left; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } #border_radius_preview #bottomRight { float: right; border-bottom: 1px solid rgba(0,0,0,.25); border-right: 1px solid rgba(0,0,0,.25); } #border_radius_preview #topLeft { border-top: 1px solid rgba(0,0,0,.25); border-left: 1px solid rgba(0,0,0,.25); border-bottom: 1px dotted rgba(0,0,0,.25); border-right: 1px dotted rgba(0,0,0,.25); } #border_radius_preview #topRight { border-top: 1px solid rgba(0,0,0,.25); border-right: 1px solid rgba(0,0,0,.25); border-bottom: 1px dotted rgba(0,0,0,.25); } #border_radius_preview #bottomLeft { border-bottom: 1px solid rgba(0,0,0,.25); border-left: 1px solid rgba(0,0,0,.25); border-right: 1px dotted rgba(0,0,0,.25); } #border_radius_preview > div.active { background: #A7D4F6; } .inactive #border_radius_preview > div.active { background: rgba(0,0,0,.08); } .options { -moz-box-shadow: 0 2px white; -webkit-box-shadow: 0 2px white; box-shadow: 0 2px white; cursor: pointer; } .options span:first-child { border-right: none; } .options span:last-child { border-left: none; } .options span { padding: 0 4px; border: 1px solid rgba(0,0,0,.5); background: -moz-linear-gradient(#C1C1C1, #D4D4D4); background: -webkit-linear-gradient(#C1C1C1, #D4D4D4); background: linear-gradient(#C1C1C1, #D4D4D4); -moz-box-shadow: 0 1px white inset; -webkit-box-shadow: 0 1px white inset; box-shadow: 0 1px white inset; } .options span.active { border: 1px solid rgba(0,0,0,.5); background: -moz-linear-gradient(#999999, #BBBBBB); background: -webkit-linear-gradient(#999999, #BBBBBB); background: linear-gradient(#999999, #BBBBBB); -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } .inactive .options span { opacity: 0.5; } #nav { width: 28%; height: 100%; float: left; cursor: default; } #nav ul { border: 1px solid #909090; -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,.3); -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,.3); box-shadow: inset 1px 1px 0 rgba(0,0,0,.3); } #nav li { margin: 0 0 0 1px; padding: 4px 6px; border-bottom: 1px solid white; cursor: pointer; } #nav li input { margin-right: 5px; vertical-align: bottom; cursor: pointer; } #nav li.active { background: #b5d5ff; font-weight: bold; } #nav li:first-child { padding-bottom: 6px; -moz-box-shadow: inset 0 -1px 0 black; -webkit-box-shadow: inset 0 -1px 0 black; box-shadow: inset 0 -1px 0 black; } #nav li:first-child + li { padding-top: 5px; border-top: 1px solid #909090; -moz-box-shadow: inset 0 1px 0 black; -webkit-box-shadow: inset 0 1px 0 black; box-shadow: inset 0 1px 0 black; } .controls { width: 18%; float: right; } .controls > div { text-align: center; } .controls > div input { margin-right: 2px; } #colorpicker { visibility: hidden; } #colorpicker .body { padding-top: 9px; } #colorpicker .main { width: 75%; height: 294px; margin-top: 21px; position: relative; } #color_field { height: 256px; width: 256px; position: absolute; } #field, #circle { position: absolute; } #circle { z-index: 999; } #color_slider { left: 259px; top: 2px; width: 44px; height: 256px; position: absolute; } #color_slider canvas { top: -2px; left: 11px; height: 256px; width: 19px; position: absolute; } .border_box { border-color: #909090 #909090 #e4e4e4 #909090; border-width: 2px 1px 1px 2px; border-style: solid; } .lightbox { border: 1px solid #909090; border-bottom-color: #e4e4e4; } #color_slider > div { left: 11px; top: 256px; width: 21px; position: absolute; } #color_slider > div > .arrow.right { right: -3px; } #color_slider > div > .arrow.left { left: -9px; } #color_slider .arrow { top: -4px; position: absolute; } #color_slider .arrow div { border: 1px solid #747474; background: white; position: absolute; } #color_slider .arrow .rear { width: 4px; height: 6px; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; } #color_slider .arrow .spike { top: 1px; width: 4px; height: 4px; -moz-transform: rotate(45deg); -webkit-transform: rotate(45deg); transform: rotate(45deg); } #color_slider .arrow.left .rear { border-right-width: 0; } #color_slider .arrow.left .spike { left: 1px; } #color_slider .arrow.right .rear { border-left-width: 0; left: 2px; } .color_preview { top: 4px; left: 304px; width: 60px; position: absolute; } .color_preview > div { height: 34px; background: black; border: 1px solid black; } #new_color { border-bottom: none; } #current_color { background: white; border-top: none; } .color_preview > label { bottom: -14px; width: 100%; text-align: center; position: absolute; } .color_preview > label:first-child { top: -20px; height: 20px; } .color_inputs { top: 111px; left: 305px; width: 100px; position: absolute; font-size: 13px; } .color_inputs ul { padding-bottom: 4px; } .color_inputs li { margin: 2px 0 3px; display: inline-block; } .color_inputs input[type=radio] { margin-right: 4px; } .color_inputs span { width: 20px; display: inline-block; } .color_inputs ul input[type=text] { width: 33px; height: 18px; margin-right: 2px; font-size: 13px; } .color_inputs #hex_holder { margin: 2px 3px; } .color_inputs #hex { height: 18px; margin-left: 4px; font-size: 13px; width: 68px; } #colorpicker .controls { width: 25%; } #swatches_holder { margin: 5px; background: #d6d6d6; border-top: 1px solid #909090; overflow: hidden; } #swatches { padding-bottom: 12px; overflow: hidden; } #swatches span { width: 10px; height: 11px; border-right: 1px solid black; border-bottom: 1px solid black; float: left; cursor: url(../img/eyedropper.gif) 0 15, auto; } .alt .swatch { cursor: url(../img/scissor.gif) 6 6, auto; } #gradient_editor { visibility: hidden; } /* overwritings */ #gradient_editor .holder { padding: 13px 9px 9px; border: 1px solid #909090; } #gradient_editor .holder h3 { left: 16px; font-size: 13px; font-weight: normal; } #gradient_editor input[type=text] { padding: 2px; font-size: 13px; } #gradient_editor .static_right { margin-right: 105px; } #gradient_editor .main { width: 100%; font-size: 13px; } #gradient_editor .static_left { margin: 16px 4px 22px 56px; } #gradient_editor .static_left > span { margin-left: -55px; line-height: 22px; float: left; } #gradient_name { width: 100%; } #gradient_new { margin-top: 17px; } #gradient_presets_holder { height: 115px; overflow: auto; } #gradient_presets div { width: 31px; height: 31px; border-right: 1px solid #909090; border-bottom: 1px solid #909090; float: left; } #gradient_editor .sidebar { width: 89px; margin-right: -105px; } #gradient_holder { padding: 12px 6px 34px; } .frame { border: 1px solid #909090; } #gradient { height: 25px; position: relative; } #gradient div { cursor: default; } #gradient .picker { position: absolute; } #gradient .picker.top { top: -19px; } #gradient .picker.bottom { top: 33px; } #gradient .picker > div { position: absolute; } #gradient .picker .arrow { left: -3px; top: 6px; height: 6px; width: 6px; border: 1px solid black; -moz-box-shadow: -1px 0 #909090 inset; -webkit-box-shadow: -1px 0 #909090 inset; box-shadow: -1px 0 #909090 inset; -moz-transform: rotate(45deg); -webkit-transform: rotate(45deg); transform: rotate(45deg); -moz-transform-origin: 2px 3px; -webkit-transform-origin: 2px 3px; transform-origin: 2px 3px; } #gradient .picker.bottom .arrow { top: -5px; -moz-box-shadow: 0 1px #909090 inset; -webkit-box-shadow: 0 1px #909090 inset; box-shadow: 0 1px #909090 inset; } #gradient .picker.selected .arrow { background: black; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } #gradient .picker .box { left: -6px; height: 10px; width: 9px; background: #E4E4E4; border: 1px solid black; border-bottom: none; -moz-box-shadow: -1px 0 #909090 inset; -webkit-box-shadow: -1px 0 #909090 inset; box-shadow: -1px 0 #909090 inset; } #gradient .picker.bottom .box { height: 9px; padding-top: 1px; border-bottom: 1px solid black; border-top: none; -moz-box-shadow: 0 1px #909090 inset; -webkit-box-shadow: 0 1px #909090 inset; box-shadow: 0 1px #909090 inset; } #gradient .picker .color_field { height: 7px; width: 7px; border-width: 1px; border-style: solid; border-color: #E4E4E4 #909090 #909090 #E4E4E4; background: black; } #gradient .middlepoint { top: -9px; position: absolute; display: none; cursor: default; } #gradient .middlepoint.visible { display: block; } #gradient .middlepoint.bottom { top: 27px; } #gradient .middlepoint span { margin-left: -4px; width: 7px; height: 7px; background: url(../img/middlepoint.gif); display: block; } #gradient .middlepoint.selected span { background-position: 0 -7px; } #gradient_editor #stops { padding: 9px 9px 2px; font-size: 13px; } #stops .disabled { color: #7f7f7f; } #stops button { width: 89px; display: inline; } #stops > div > div { width: 140px; display: inline-block; } #stops span { width: 54px; margin-right: 4px; text-align: right; display: inline-block; } #stops input[type="text"] { margin-right: 2px; } #stop_color { width: 45px; height: 18px; margin-bottom: -5px; border: 1px solid #909090; display: inline-block; cursor: pointer; } .disabled #stop_color { cursor: auto; } .eyedropper { cursor: url(../img/eyedropper.gif) 0 15, auto; } .colorcircle { cursor: url(../img/colorcircle.gif) 8 8, auto; } .paint_bucket { cursor: url(../img/paint_bucket.gif) 13 14, auto; } .resize { cursor: url(../img/resize.gif) 8 8, se-resize; } .pot { margin: 0 3px; width: 40px; height: 40px; background: -moz-linear-gradient(top, #dbdbdb, #e1e1de 20%, #f8f8f3); background: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), color-stop(50%, #e1e1de), to(#f8f8f3)); border: 2px solid #727272; -moz-box-shadow: inset 0 2px 3px white, inset 0 -1px 2px #fffef8; -webkit-box-shadow: inset 0 2px 3px white, inset 0 -1px 2px #fffef8; box-shadow: inset 0 2px 3px white, inset 0 -1px 2px #fffef8; -moz-border-radius: 40px; -webkit-border-radius: 40px; border-radius: 40px; position: relative; display: inline-block; } .pointer { top: 50%; left: 50%; margin: -1.5px 0 0 -1.5px; width: 50%; -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); transform: rotate(-90deg); -moz-transform-origin: 1.5px 1.5px; -webkit-transform-origin: 1.5px 1.5px; transform-origin: 1.5px 1.5px; position: absolute; } .dot { height: 3px; width: 3px; background: #909090; position: absolute; } .line { margin-top: 1px; height: 1px; background: #909090; } .slider { padding: 4px 0 2px 1px; position: relative; display: inline-block; } .slider .bar { margin-top: 3px; height: 3px; background: -moz-linear-gradient(top, #adadad, #b2b2b2); background: -webkit-gradient(linear, left top, left bottom, from(#adadad), to(#b2b2b2)); -moz-box-shadow: inset 0 1px 0 #929292; -webkit-box-shadow: inset 0 1px 0 #929292; box-shadow: inset 0 1px 0 #929292; border: 1px solid #686868; border-bottom-color: #aaa; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } .inactive .slider .bar { background: -moz-linear-gradient(top, #bfbfbf, #d0d0d0); background: -webkit-linear-gradient(top, #bfbfbf, #d0d0d0); background: linear-gradient(top, #bfbfbf, #d0d0d0); -moz-box-shadow: inset 0 1px 0 #bfbfbf; -webkit-box-shadow: inset 0 1px 0 #bfbfbf; box-shadow: inset 0 1px 0 #bfbfbf; border-color: #aaa #aaa #cacaca; } .slider .arrow { left: 0; top: 3px; position: absolute; } .slider .rear { left: -3px; top: 4px; height: 5px; width: 7px; background: -moz-linear-gradient(top, #a7d4f6, #73bbf2, #b0e9fd); background: -webkit-gradient(linear, left top, left bottom, from(#a7d4f6), color-stop(50%,#73bbf2), to(#b0e9fd)); border: 1px solid #787a96; border-top-width: 0; -moz-border-radius: 0 0 2px 2px; -webkit-border-radius: 2px; border-radius: 2px; -moz-box-shadow: 0 1px 0 rgba(0,0,0,.05); position: relative; } .slider .spike { left: -4px; height: 4px; width: 4px; background: -moz-linear-gradient(-45deg, #e4f1fc, #88c4f2); background: -webkit-gradient(linear, left top, right bottom, from(#e4f1fc), to(#88c4f2)); border: 1px solid #8d84ae; -moz-transform-origin: 3px 7px; -webkit-transform-origin: 3px 7px; transform-origin: 3px 7px; -moz-transform: rotate(45deg); -webkit-transform: rotate(45deg); transform: rotate(45deg); position: absolute; } .inactive .slider .rear { background: -moz-linear-gradient(#ECEDED, #DBDBDB, #EBEBEB); background: -webkit-linear-gradient(#ECEDED, #DBDBDB, #EBEBEB); background: linear-gradient(#ECEDED, #DBDBDB, #EBEBEB); border-color: #7F7D7D; } .inactive .slider .spike { background: -moz-linear-gradient(-45deg, #E1E1E1, white); background: -webkit-linear-gradient(-45deg, #E1E1E1, white); background: linear-gradient(-45deg, #E1E1E1, white); border-color: #9E9E9E; } button { width: 100%; margin: 8px 0; padding: 1px 0; background: -moz-linear-gradient(top, #fcfcfc, #f4f4f4 40%, #e6e6e5 42%, #f5f5f5 75%, #fff); background: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), color-stop(40%,#f4f4f4), color-stop(42%,#e6e6e5), color-stop(75%,#f5f5f5), to(#fff)); font-size: 12px; border: 1px solid #7d7d7d; -moz-border-radius: 17px; -webkit-border-radius: 17px; border-radius: 17px; -moz-box-shadow: 0 1px 0 rgba(0,0,0,.2); -webkit-box-shadow: 0 1px 0 rgba(0,0,0,.2); box-shadow: 0 1px 0 rgba(0,0,0,.2); display: block; outline: none; cursor: pointer; } button::-moz-focus-inner { border: 0; } /* firefox outline removed */ button:first-child { margin-top: 0; } label[for] { cursor: pointer; } #puff { width: 22px; height: 22px; background: url(../img/puff.png); position: absolute; display: block; z-index: 110; } .clear { clear: both; } ================================================ FILE: index.html ================================================ Layer Styles

LayerStyles

just like your favorite graphics editor

but in your browser. And it creates CSS.

Layerstyles main interface
Layerstyles main interface

Unfortunately your browser doesn't support the following requirements:

Javascript enabled Native JSON CSS Background Gradients Border Radius HTML5 Canvas HTML5 Flexbox RGB Alpha-Channel Box Shadows

Please update your browser.

================================================ FILE: js/application.js ================================================ /*! * _ ________ _ * | | | ______| | | * | | | | _ | | * | | _____ ___ ___ _____ _____ | |______ _| |_ ___ ___ | | _____ _____ * | | | _ |\ \/ /| _ || __| |______ ||_ _|\ \/ / | | | _ || ___| * | |_____ | |_| | / / | ___|| | ______| | | | / / | |___ | ___||___ | * |_______||___,\|/___/ |_____||__| |________| |_| /___/ |_____||_____||_____| * * http://www.layerstyles.org * * Copyright (c) 2011 Felix Niklas * This script is freely distributable under the terms of the MIT license. */ localStorage['version'] = "0.1"; var movePos = { x: 0, y: 0 }, bytes, reader; var $body = $('body'); var $overlay = $('#overlay'); var $workspace = $('#workspace'); var dimensions = { width: $workspace.width(), height: $workspace.height() }; var $dialog = $('#dialog'); var $layerstyle = $('#layerstyle'); var $navElements = $('#nav ul li'); var $holderElements = $('#holder > div'); var $pots = $('.pot'); var potDimensions = {'height': 40, 'width': 40}; var $sliders = $('.slider'), shouldEase = false; var $numericalInputs = $('input[type=text]', $dialog); var $buttons = { 'ok': $('#ok'), 'cancel': $('#cancel'), 'newStyle': $('#new_style') }; var $layer = $('#layer'); var resizeArea = $('#resize'); var $backgroundLayer = $('#background_layer');//.css("height", dimensions.height); var $parallelUniverse = $('#parallel_universe').attr({height: dimensions.height, width: dimensions.width}); var pu = $parallelUniverse.get(0).getContext('2d'); var $innerShadowUniverse = $('#innerShadow_universe').attr({height: dimensions.height, width: dimensions.width}); var iu = $innerShadowUniverse.get(0).getContext('2d'); var moveAreas = $('.moveable'), movingWindow; var offset = { x: 0, y: 0 }; var $colorfields = $('.color_field'); var currentStyle, lang; var background = { background: [{ stops: [[255,255,255,1], [255,255,255,0]], style: 'radial', position: 'center', angle: 90 }, { stops: [[226, 226, 226], [171, 171, 171]], style: 'linear', angle: 90 } ] }; // array compare function - thanks to David and Anentropic // http://stackoverflow.com/questions/1773069/using-jquery-to-compare-two-arrays // (sort removed and extended to deep comparison) // syntax: $.compare(a, b); jQuery.extend({ compare: function (b, a) { if (a.length != b.length) { return false; } for (var i = 0, l = a.length; i < l; i++) { if (a[i] !== b[i]) { if(typeof a[i] === 'object'){ return jQuery.compare(a[i],b[i]); } else { return false; } } } return true; } }); // Object.create implementation for older browsers // by Ben Newman if(Object.create === undefined){ Object.create = function( proto, props ) { var ctor = function( ps ) { if ( ps ) Object.defineProperties( this, ps ); }; ctor.prototype = proto; return new ctor( props ); }; } /* things to store: - styles, gradients and colors - layerstyles version - currentStyle */ var defaults = { height: 300, width: 300, ratio: 1, globalAngle: 90, dropShadow: { isActive: true, color: [0,0,0], opacity: 75, angle: 90, hasGlobalLight: false, distance: 1, blur: 5, size: 0 }, innerShadow: { isActive: false, color: [255,255,255], opacity: 100, angle: 90, hasGlobalLight: false, distance: 1, blur: 0, size: 0, isInset: true }, background: { isActive: true, opacity: 100, stops: [[252, 252, 252], 23, [[242, 242, 242], 12], 89, [191, 191, 191]], isReverse: false, style: 'linear', angle: 90, hasGlobalLight: false }, border: { isActive: true, color: [0,0,0], opacity: 100, size: 1, style: 'solid' }, borderRadius: { isActive: false, radii: [[0, "px"],[0, "px"],[0, "px"],[0, "px"]], isSelected: [true,true,true,true], hasPercentage: [false, false, false, false] } }; var nav = { $el: $layerstyle, $pages: null, width: null, page: null, prev: null, speed: 0, goTo: function(pageNr){ // parse Int pageNr = pageNr*1; localStorage["pageNr"] = pageNr; if(pageNr === -1){ pageNr = this.prev; // go back } else { pageNr--; // pages area 1,2,3 - but in the array they are 0,1,2 } var goPage = this.$pages.eq(pageNr); var currentPage = this.$pages.eq(this.page); var direction = pageNr > this.page ? 1 : -1; // 1 = right, -1 = left var offset = this.width; this.$el.css('overflow', 'hidden'); currentPage .animate({ 'margin-left': -direction*offset+'px', 'opacity': 0 }, this.speed, function(){ nav.$pages.eq(nav.page).css('visibility', 'hidden'); }); goPage .css({ 'margin-left': direction*offset+'px', 'visibility': 'visible', 'opacity': 0 }) .animate({ 'margin-left': 0, 'opacity': 1 }, this.speed, function(){ nav.$el.css('overflow', 'visible'); }); this.prev = this.page; this.page = pageNr; }, show: function(pageNr){ pageNr--; $(this.$pages[pageNr]).css('visibility', 'visible'); this.page = pageNr; }, init: function(){ this.width = this.$el.width(); this.$pages = $('> .window', this.$el); this.show(1); } } function moveWindow(event){ movingWindow.css({ top: event.pageY - movePos.y, left: event.pageX - movePos.x }); } function resizeLayer(event, x, y){ var halfWidth, halfHeight, maxWidth, maxHeight; halfWidth = parseInt(( x != null ? x/2 : event.pageX - dimensions.width/2 + offset.x), 10); halfHeight = event != null && event.shiftKey ? halfWidth / currentStyle.ratio : parseInt(( y != null ? y/2 : event.pageY - dimensions.height/2 + offset.y), 10); maxWidth = dimensions.width/2; maxHeight = dimensions.height/2; halfWidth = halfWidth < 8 ? 8 : halfWidth > maxWidth ? maxWidth : halfWidth; halfHeight = halfHeight < 8 ? 8 : halfHeight > maxHeight ? maxHeight : halfHeight; currentStyle.width = halfWidth*2; currentStyle.height = halfHeight*2; $layer.css({ 'width': currentStyle.width, 'height': currentStyle.height, 'margin-top': -halfHeight, 'margin-left': -halfWidth }); } function showSlide(pos){ $navElements.removeClass('active'); $navElements.eq(pos).addClass('active'); $holderElements.removeClass('active').eq(pos).addClass('active'); } function dragenter(e) { e.stopPropagation(); e.preventDefault(); $body.addClass("dragging"); } function dragleave(e) { e.stopPropagation(); e.preventDefault(); $body.removeClass("dragging"); } function dragover(e) { e.stopPropagation(); e.preventDefault(); } function drop(e) { e.stopPropagation(); e.preventDefault(); dropPos = { x: e.pageX, y: e.pageY }; var dt = e.dataTransfer; var files = dt.files; for (var i = 0, l=files.length; i < l; i++) { var data = files[i]; //bytes = new Stream(data); reader = new FileReader(); reader.onload = function(e){ var img = new Image(), $canvas = $(""), ctx = $canvas.get(0).getContext('2d'); img.src = e.target.result; img.onload = function(){ $canvas.attr({ title: data.name, width: img.width, height: img.height }); $canvas.css({ left: dropPos.x-img.width/2, top: dropPos.y-img.height/2, position: "absolute" }); $canvas.addClass("moveable"); ctx.drawImage(img, 0, 0); $canvas.appendTo($workspace); }; }; reader.readAsDataURL(data); } $body.removeClass("dragging"); } function showPickArea(){ $body.addClass("pick"); // draw the parallel Universe for color picking parallelUniverse.draw(); // redraw the parallelUniverse when the layer gets redrawn ("paint" event); $(document).bind('paint', $.proxy( parallelUniverse, "draw" )); $overlay.bind('mousedown', pick); } function hidePickArea(){ $body.removeClass("pick"); $(document).unbind('paint', $.proxy( parallelUniverse, "draw" )); $overlay.unbind('mousedown'); } function pick(event){ var pickedColor = pu.getImageData(event.pageX, event.pageY, 1, 1).data; colorpicker.setHex(color.hexFromRgb(pickedColor)); colorpicker.update('hex'); } function initialise() { // include 'dataTransfer' to jquerys event object jQuery.event.props.push('dataTransfer'); // set language // not yet elaborated - whats the best solution to change all titles in the html? // - create the html via js in the first place or select and change them all? // - regex over the all textnodes? lang = localization.en; $navElements.click(function(){ var pos = $navElements.index(this); localStorage["slidePos"] = pos; showSlide(pos); }); $numericalInputs.bind({ mousedown: function(e){ e.stopPropagation(); }, focus: function(e){ numbers.initNumberField(this, 'style'); }, keydown: numbers.restrictCharacters, keyup: numbers.keyUp, blur: numbers.validateInput }); moveAreas.live('mousedown', function(event){ event.preventDefault(); movingWindow = $(this).hasClass("head") ? $(this).parents('#layerstyle') : $(this); movingWindow.addClass("moving"); $(document).one('mouseup', function(){ movingWindow.removeClass("moving"); }); var myOffset = movingWindow.offset(); movePos = { x:event.pageX-myOffset.left, y:event.pageY-myOffset.top }; $(document).bind('mousemove.global', moveWindow); }); resizeArea.bind({ mousedown: function(event){ event.preventDefault(); event.stopPropagation(); currentStyle.ratio = currentStyle.width/currentStyle.height; $(document).bind('mousemove.global', resizeLayer); $body.addClass("resize"); $(document).one('mouseup', function(){ $body.removeClass('resize'); }); var my_offset = $(this).offset(); offset = { x: 15-(event.pageX-my_offset.left), y: 15-(event.pageY-my_offset.top) }; }, click: function(event){ event.stopPropagation(); } // prevent bubbling }); $(document).bind({ mousemove: function(e){ e.preventDefault(); }, mouseup: function(){ $(this).unbind('mousemove.global'); }, dragenter: dragenter, dragleave: dragleave, dragover: dragover, drop: drop }); $(window).bind({ resize: function(event){ dimensions = { width: $workspace.width(), height: $workspace.height() }; $parallelUniverse.attr({'width': dimensions.width, 'height': dimensions.height}); $innerShadowUniverse.attr({'width': dimensions.width, 'height': dimensions.height}); if (dimensions.width < currentStyle.width) { resizeLayer(null, dimensions.width, currentStyle.height); } if (dimensions.height < currentStyle.height) { resizeLayer(null, currentStyle.width, dimensions.height); } }, keydown: function(event){ if(event.altKey){ $body.addClass('alt'); $(this).one('keyup', function(){ $body.removeClass('alt'); }); } } }); $layer.dblclick(function(event){ $layerstyle.show(); }); $buttons.ok.click(function(){ $layerstyle.hide(); }); $buttons.cancel.click(function(){ $layerstyle.hide(); }); $buttons.newStyle.click( $.proxy( styleStore, "create" ) ); $('#infoButton').click(function(){ $body.removeClass('visited'); }); styleStore.init(); nav.init(); colorpicker.init(); gradienteditor.init(); codeBox.init(); style.init(); showSlide(localStorage["slidePos"] || 1); nav.goTo(localStorage["pageNr"] || 1); $(document) .bind('paint', $.proxy( codeBox, "render" )) .bind('paint', $.proxy( css, "render" )) .trigger('styleChange') .trigger('paint'); } // isEven: (n % 2) == 0 -> true? even : odd // GET THE BALL ROLLIN $(document).ready(function(){ initialise(); }); ================================================ FILE: js/codebox.js ================================================ var codeBox = { options: { visible: true, height: 143 }, minHeight: 100, init: function(){ if(localStorage["codeBoxOptions"]) this.options = JSON.parse(localStorage["codeBoxOptions"]); this.$el = $('#codeBox'); this.$box = this.$el.find('code'); this.$body = this.$el.find('.body'); this.$copyCode = this.$el.find('#copyCode'); this.$dragger = this.$el.find('.dragger.y'); this.$codeBoxToggle = $('#codeBoxToggle'); this.$colorToggle = Object.create(toggle); this.$colorToggle.init("colorSwitch", "hex", tools.options, $.proxy( this, "render" )); this.location = window.location.href.slice(0, window.location.href.lastIndexOf("/")); this.initClipboard(); this.$copyCode.add(this.$body).add(this.$box) .bind('mousedown', function(e){ e.stopPropagation(); }); this.$codeBoxToggle.click( $.proxy( this, "toggle" ) ); this.$dragger.mousedown( $.proxy( this, "drag") ); this.updateView(); }, toggle: function(){ if(this.$el.height() === 0){ this.options.visible = true; } else { this.options.visible = false; } this.storeSettings(); this.updateView(); $(window).trigger('resize'); }, updateView: function(){ if(this.options.visible){ this.$el.height(this.options.height); } else { this.$el.height(0); } }, drag: function(event){ event.preventDefault(); var my_offset = $(event.target).offset(); offset = { y: event.pageY-my_offset.top }; this.$el.addClass("resizing"); this.resize(event); $(document).one('mouseup', function(){ codeBox.$el.removeClass('resizing') } ); $(document).bind('mousemove.global', $.proxy( this, "resize") ); }, resize: function(event){ this.options.height = Math.max(this.minHeight, $(document).height() - event.pageY + offset.y); this.$el.height(this.options.height); $(window).trigger('resize'); this.storeSettings(); }, storeSettings: function(){ localStorage["codeBoxOptions"] = JSON.stringify(this.options); }, /** * @method initClipboard - a click on the button with the id 'copyCode' will copy 'this.$box.text()' into the clipboard * @see http://code.google.com/p/zeroclipboard/wiki/Instructions */ initClipboard: function(){ ZeroClipboard.setMoviePath( this.location + '/js/zeroclipboard/ZeroClipboard.swf' ); this.clip = new ZeroClipboard.Client(); this.clip.addEventListener( 'onMouseDown', $.proxy( this, "copy" ) ); this.clip.setHandCursor(true); var flash = this.clip.getHTML(this.$copyCode.width(), this.$copyCode.height()); this.$copyCode.append(flash); }, copy: function(){ var text = this.code.replace(/
/g, "\n").replace(/ /g, ""); this.clip.setText(text); }, tabs: function(count){ var tabString = "", tabs = count || this.options.tabs; for(;tabs--;){ tabString += " "; } return tabString; }, render: function(){ var borderRadiusObject; this.code = ""; // add border this.code += currentStyle.border.isActive ? "border: " + css.border(currentStyle) + ";
" : ""; // add border-radius if(currentStyle.borderRadius.isActive){ borderRadiusObject = css.borderRadius(currentStyle); for(var key in borderRadiusObject){ var radius = borderRadiusObject[key]; if(radius !== 0){ this.code += key + ": " + radius + ";
"; } } } // add gradient if(currentStyle.background.isActive){ this.code += "background-image: " + css.drawGradient(currentStyle) + ";
"; } // add dropShadow and innerShadow if(currentStyle.dropShadow.isActive || currentStyle.innerShadow.isActive){ this.code += "box-shadow: " + css.boxShadow(currentStyle) + ";
"; } this.$box.html(this.code); } }; ================================================ FILE: js/color.js ================================================ var color = { hsbFromRgb: function(rgb) { r = rgb[0]/255, g = rgb[1]/255, b = rgb[2]/255; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; s = max === 0 ? 0 : d / max; if(max === min){ h = 0; }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 [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)]; }, rgbFromHsb: function(hsv) { var r, g, b; h = hsv[0]/360; s = hsv[1]/100; v = hsv[2]/100; var i = Math.floor(h * 6); var f = h * 6 - i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); switch(i % 6){ case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; }, rgbFromHex: function(hex){ if(hex.length === 3){ return [ parseInt(hex.substring(0,1)+hex.substring(0,1), 16), parseInt(hex.substring(1,2)+hex.substring(1,2), 16), parseInt(hex.substring(2,3)+hex.substring(2,3), 16) ] } else { return [ parseInt(hex.substring(0,2), 16), parseInt(hex.substring(2,4), 16), parseInt(hex.substring(4,6), 16) ] } }, hexFromRgb: function(rgb){ var hexcode = this.toHex(rgb[0])+this.toHex(rgb[1])+this.toHex(rgb[2]), parts = hexcode.split(""); // "000" instead of "000000" return (parts[0]===parts[1]) && (parts[2]===parts[3]) && (parts[4]==parts[5]) ? parts[0]+parts[2]+parts[4] : hexcode; }, toHex: function(n) { if(n === 0) { return '00'; } n = parseInt(n, 10); if (n === 0 || isNaN(n)) { return "00"; } return "0123456789abcdef".charAt((n-n%16)/16) + "0123456789abcdef".charAt(n%16); } }; ================================================ FILE: js/colorpicker.js ================================================ /* * LayerStyles * http://www.layerstyles.org * * Copyright (c) 2011 Felix Niklas * This script is freely distributable under the terms of the MIT license. */ var colorpicker = { open: false, currentColor: "000000", // hex callback: null, thisArg: null, swatches: [ {'title': 'White', 'hex': 'ffffff'}, {'title': '10% Gray', 'hex': 'e5e5e5'}, {'title': '20% Gray', 'hex': 'cccccc'}, {'title': '30% Gray', 'hex': 'b3b3b3'}, {'title': '40% Gray', 'hex': '999999'}, {'title': '50% Gray', 'hex': '808080'}, {'title': '60% Gray', 'hex': '666666'}, {'title': '70% Gray', 'hex': '4d4d4d'}, {'title': '80% Gray', 'hex': '333333'}, {'title': '90% Gray', 'hex': '1a1a1a'}, {'title': 'Black', 'hex': '000000'} ], $selectedInput: null, colorHistory: [], pointerPos: { 'x': 0, 'y': 0 }, hsb: { h: 0, s: 0, b: 0 }, rgb: { r: 0, g: 0, b: 0 }, hex: '000000', mode: 'hsb_b', max: 0, // the maximum input value ratio: 0, // the ratio for the slider: its 0.7111 (hue), ~1 (rgb) or 2.56 (saturation/brightness) offset: 0, // the offset relative to the document will be stored in here to calculate mouse-dragging pick: function(rgbArray, callback, thisArg) { showPickArea(); this.callback = callback; this.thisArg = thisArg; // set rgb this.setRgb(parseInt(rgbArray[0],10),parseInt(rgbArray[1],10),parseInt(rgbArray[2],10)); // update this.update('rgb_r'); // set currentColor this.setCurrentColor(); // show it nav.goTo(3); }, setCurrentColor: function(hex) { this.currentColor = hex || this.hex; this.$currentColor.css('background', '#'+this.currentColor); }, pickCurrentColor: function(){ this.setHex(this.currentColor); this.update('hex'); }, clickHex: function(){ this.$hex.focus(); }, update: function(customMode) { var updateMode = customMode || this.mode; switch(updateMode){ case 'hsb_h': case 'hsb_s': case 'hsb_b': this.getHsb(); this.hsbToRgb(); this.rgbToHex(); break; case 'rgb_r': case 'rgb_g': case 'rgb_b': this.getRgb(); this.rgbToHsb(); this.rgbToHex(); break; case 'hex': this.getHex(); this.hexToRgb(); this.rgbToHsb(); break; } this.paintField(); this.paintSlider(); this.setNewColor(); this.moveSlider(this.$selectedInput.val()*this.ratio); if(this.callback) this.callback.call(this.thisArg, color.rgbFromHex(this.hex)); }, paintField: function() { var xGradient, yGradient; this.cf.save(); this.cf.clearRect(0,0,256,256); xGradient = this.cf.createLinearGradient(0, 0, 0, 256); yGradient = this.cf.createLinearGradient(0, 0, 256, 0); switch (this.mode) { case 'hsb_h': // rainbow var hue = color.rgbFromHsb([this.hsb.h, 100, 100]); yGradient.addColorStop(0, 'white'); yGradient.addColorStop(1, 'rgb('+hue[0]+','+hue[1]+','+hue[2]+')'); xGradient.addColorStop(0, 'transparent'); xGradient.addColorStop(1, 'black'); break; case 'hsb_s': // rainbow yGradient.addColorStop(0, 'rgb(255,0,0)'); yGradient.addColorStop(1/6, 'rgb(255,255,0)'); yGradient.addColorStop(2/6, 'rgb(0,255,0)'); yGradient.addColorStop(3/6, 'rgb(0,255,255)'); yGradient.addColorStop(4/6, 'rgb(0,0,255)'); yGradient.addColorStop(5/6, 'rgb(255,0,255)'); yGradient.addColorStop(1, 'rgb(255,0,0)'); xGradient.addColorStop(0, 'rgba(0,0,0,'+(1-this.hsb.s/100)+')' ); xGradient.addColorStop(1, 'black' ); break; case 'hsb_b': // rainbow from saturated to unsaturated var grey = parseInt(this.hsb.b*2.56, 10); yGradient.addColorStop(0, 'rgb(255,0,0)'); yGradient.addColorStop(1/6, 'rgb(255,255,0)'); yGradient.addColorStop(2/6, 'rgb(0,255,0)'); yGradient.addColorStop(3/6, 'rgb(0,255,255)'); yGradient.addColorStop(4/6, 'rgb(0,0,255)'); yGradient.addColorStop(5/6, 'rgb(255,0,255)'); yGradient.addColorStop(1, 'rgb(255,0,0)'); xGradient.addColorStop(0, 'rgba('+grey+','+grey+','+grey+','+(1-this.hsb.b/100)+')'); xGradient.addColorStop(1, 'rgb('+grey+','+grey+','+grey+')'); break; case 'rgb_r': this.cf.globalCompositeOperation = 'lighter'; xGradient.addColorStop(0, 'rgb('+this.rgb.r+',255,0)'); xGradient.addColorStop(1, 'rgb('+this.rgb.r+',0,0)'); yGradient.addColorStop(0, 'rgb('+this.rgb.r+',0,0)'); yGradient.addColorStop(1, 'rgb('+this.rgb.r+',0,255)'); break; case 'rgb_g': this.cf.globalCompositeOperation = 'lighter'; xGradient.addColorStop(0, 'rgb(255,'+this.rgb.g+',0)'); xGradient.addColorStop(1, 'rgb(0,'+this.rgb.g+',0)'); yGradient.addColorStop(0, 'rgb(0,'+this.rgb.g+',0)'); yGradient.addColorStop(1, 'rgb(1,'+this.rgb.g+',255)'); break; case 'rgb_b': this.cf.globalCompositeOperation = 'lighter'; xGradient.addColorStop(0, 'rgb(0,255,'+this.rgb.b+')'); xGradient.addColorStop(1, 'rgb(0,0,'+this.rgb.b+')'); yGradient.addColorStop(0, 'rgb(0,0,'+this.rgb.b+')'); yGradient.addColorStop(1, 'rgb(255,0,'+this.rgb.b+')'); break; } this.cf.beginPath(); this.cf.rect(0, 0, 256, 256); this.cf.closePath(); this.cf.fillStyle = yGradient; this.cf.fill(); this.cf.beginPath(); this.cf.rect(0, 0, 256, 256); this.cf.closePath(); this.cf.fillStyle = xGradient; this.cf.fill(); this.cf.restore(); this.movePointer(); }, startPointer: function(event) { this.offset = this.$circleField.offset(); this.calculatePointer(event); $(document).bind('mousemove.global', jQuery.proxy(this, "calculatePointer")); }, calculatePointer: function(event) { event.preventDefault(); this.pointerPos.x = Math.max(0, Math.min(256, event.pageX-this.offset.left)); this.pointerPos.y = Math.max(0, Math.min(256, event.pageY-this.offset.top)); switch(this.mode){ case 'hsb_h': this.$hsb_s.val(parseInt(this.pointerPos.x/2.56, 10)); this.$hsb_b.val(100-parseInt(this.pointerPos.y/2.56, 10)); break; case 'hsb_s': this.$hsb_h.val(parseInt(this.pointerPos.x/0.71111, 10)); this.$hsb_b.val(100-parseInt(this.pointerPos.y/2.56, 10)); break; case 'hsb_b': this.$hsb_h.val(parseInt(this.pointerPos.x/0.71111, 10)); this.$hsb_s.val(100-parseInt(this.pointerPos.y/2.56, 10)); break; case 'rgb_r': this.$rgb_b.val(parseInt(this.pointerPos.x/1.003921, 10)); this.$rgb_g.val(255-parseInt(this.pointerPos.y/1.003921, 10)); break; case 'rgb_g': this.$rgb_b.val(parseInt(this.pointerPos.x/1.003921, 10)); this.$rgb_r.val(255-parseInt(this.pointerPos.y/1.003921, 10)); break; case 'rgb_b': this.$rgb_r.val(parseInt(this.pointerPos.x/1.003921, 10)); this.$rgb_g.val(255-parseInt(this.pointerPos.y/1.003921, 10)); break; } this.movePointer(); this.update(); }, movePointer: function(x, y) { this.pointerPos.x = x >= 0 ? x : this.pointerPos.x; this.pointerPos.y = y >= 0 ? y : this.pointerPos.y; this.cc.clearRect(0,0,256,256); // limit x and y to 0-255 cause we need +1 (=256) space to detect the underlaying color var detectX = Math.min(255, this.pointerPos.x), detectY = Math.min(255, this.pointerPos.y); var background = this.cf.getImageData(detectX, detectY, 1, 1).data; // check if the underlying color is dark or light and set the circle color according to that // -> white circle if the underlying color is dark (treshhold of 128 - where 256 is white) - otherwise black this.cc.strokeStyle = ((background[0]+background[1]+background[2])/3) < 128 ? 'white' : 'black'; this.cc.beginPath(); this.cc.arc(detectX + 0.5, detectY + 0.5, 5, 0, Math.PI*2, true); this.cc.closePath(); this.cc.stroke(); }, drawPointer: function() { var posX = 0, posY = 0; switch(this.mode){ case 'hsb_h': posX = this.hsb.s*2.56; posY = (100-this.hsb.b)*2.56; break; case 'hsb_s': posX = this.hsb.h*0.71111; posY = (100-this.hsb.b)*2.56; break; case 'hsb_b': posX = this.hsb.h*0.71111; posY = (100-this.hsb.s)*2.56; break; case 'rgb_r': posX = this.rgb.b*1.003921; posY = (255-this.rgb.g)*1.003921; break; case 'rgb_g': posX = this.rgb.b*1.003921; posY = (255-this.rgb.r)*1.003921; break; case 'rgb_b': posX = this.rgb.r*1.003921; posY = (255-this.rgb.g)*1.003921; break; } this.movePointer(parseInt(posX, 10), parseInt(posY, 10)); }, paintSlider: function() { var gradient = this.cs.createLinearGradient(0, 0, 0, 256); this.cs.clearRect(0,0,19,256); switch (this.mode) { case 'hsb_h': // rainbow gradient.addColorStop(0, 'rgb(255,0,0)'); gradient.addColorStop(1/6, 'rgb(255,0,255)'); gradient.addColorStop(2/6, 'rgb(0,0,255)'); gradient.addColorStop(3/6, 'rgb(0,255,255)'); gradient.addColorStop(4/6, 'rgb(0,255,0)'); gradient.addColorStop(5/6, 'rgb(255,255,0)'); gradient.addColorStop(1, 'rgb(255,0,0)'); break; case 'hsb_s': // max saturation to unsaturated var brightness = this.hsb.b; if(brightness <= 33) brightness = 33; var saturated = color.rgbFromHsb([this.hsb.h, 100, brightness]); var unsaturated = color.rgbFromHsb([this.hsb.h, 0, brightness]); gradient.addColorStop(0, 'rgb('+saturated[0]+','+saturated[1]+','+saturated[2]+')'); gradient.addColorStop(1, 'rgb('+unsaturated[0]+','+unsaturated[1]+','+unsaturated[2]+')'); break; case 'hsb_b': // max brightness to black var brightest = color.rgbFromHsb([this.hsb.h, this.hsb.s, 100]); gradient.addColorStop(0, 'rgb('+brightest[0]+','+brightest[1]+','+brightest[2]+')'); gradient.addColorStop(1, 'black'); break; case 'rgb_r': gradient.addColorStop(0, 'rgb(255,'+this.rgb.g+','+this.rgb.b+')'); gradient.addColorStop(1, 'rgb(0,'+this.rgb.g+','+this.rgb.b+')'); break; case 'rgb_g': gradient.addColorStop(0, 'rgb('+this.rgb.r+',255,'+this.rgb.b+')'); gradient.addColorStop(1, 'rgb('+this.rgb.r+',0,'+this.rgb.b+')'); break; case 'rgb_b': gradient.addColorStop(0, 'rgb('+this.rgb.r+','+this.rgb.g+',255)'); gradient.addColorStop(1, 'rgb('+this.rgb.r+','+this.rgb.g+',0)'); break; } this.cs.beginPath(); this.cs.rect(0, 0, 19, 256); this.cs.closePath(); this.cs.fillStyle = gradient; this.cs.fill(); }, startSlider: function(event) { this.offset = this.$slideArea.offset(); this.slide(event); $(document).bind('mousemove.global', jQuery.proxy(this, "slide")); }, slide: function(event) { event.preventDefault(); var relativePosition = event.pageY - this.offset.top; if(relativePosition < 0) relativePosition = 0; if(relativePosition > 256) relativePosition = 256; // invert the value because the browsers coordination system has its origin at the top but the slider has its origin at the bottom relativePosition = 256 - relativePosition; this.moveSlider(relativePosition); this.$selectedInput.val(parseInt(relativePosition/this.ratio, 10)); this.update(); }, moveSlider: function(position) { this.$slider.css({'top':(256-position)+'px'}); }, getHsb: function() { this.hsb.h = this.$hsb_h.val(); this.hsb.s = this.$hsb_s.val(); this.hsb.b = this.$hsb_b.val(); }, getRgb: function() { this.rgb.r = this.$rgb_r.val(); this.rgb.g = this.$rgb_g.val(); this.rgb.b = this.$rgb_b.val(); }, getHex: function() { var hex = this.$hex.val(); var missingLength = 6 - hex.length; if(missingLength === 3){ var parts = hex.split(""); hex = parts[0]+parts[0]+parts[1]+parts[1]+parts[2]+parts[2]; } else { for(var i = 0; i') .attr({'title': title, 'data-hex': hex}) .css({'background': '#'+hex}) .bind('click', {self: this}, this.handleSwatch); }, handleSwatch: function(e){ e.stopPropagation(); var self = e.data.self; // if alt is pressed while clicking: remove swatch if(e.altKey){ // find out the swatches position in the swatch array var position = 0; var family = $(this).parent().children(); for(var i = 0, length = family.length; i'); for(var i = 0, length = this.swatches.length; i div'); this.cf = $('#field').get(0).getContext('2d'); this.cc = $('#circle').get(0).getContext('2d'); this.cs = this.$slideArea.find('canvas').get(0).getContext('2d'); if(localStorage["swatches"]) this.swatches = JSON.parse(localStorage["swatches"]); this.$currentColor.click( jQuery.proxy(this, "pickCurrentColor") ); this.$button_ok.click( jQuery.proxy(this, "okAction") ); this.$button_cancel.click( jQuery.proxy(this, "cancelAction") ); this.$circleField.mousedown( jQuery.proxy(this, "startPointer") ); this.$slideArea.mousedown( jQuery.proxy(this, "startSlider") ); this.$textHolder.bind('click', {self: this}, this.clickAll); this.$hexHolder.click( jQuery.proxy(this, "clickHex") ); this.$hex.bind({ focus: function(){ numbers.initHexField(this, 'color'); }, keydown: numbers.restrictCharacters, keyup: numbers.keyUp }); this.$textInputs.bind({ focus: function(){ numbers.initNumberField(this, 'color'); }, keydown: numbers.restrictCharacters, keyup: numbers.keyUp, blur: numbers.validateInput }); this.$swatchHolder.bind('click', {self: this}, this.newSwatch); // find initial checked input this.findCheckedInput(); // draw swatches this.drawSwatches(); this.update(); } }; ================================================ FILE: js/css.js ================================================ var css = { colors: { 'rgb(0,0,0)': "black", 'rgb(255,255,255)': "white" }, gradientDirections: { 315: "to bottom right", 270: "to bottom", 225: "to bottom left", 180: "to left", 135: "to top left", 90: "to top", 45: "to top right", 0: "to right" }, /** * @method cssGradient * @param gradient {object} * @return {array} decoded color stops: rgb strings * @example cssGradient([0,0,0], 10, [255,255,255]) returns "-moz-linear-gradient(top, 'rgb(0,0,0)', 'rgb(25,25,25) 10%', 'rgb(255,255,255)')" */ cssGradient: function(stops, angle, style){ var tempStops, shape = "", cssString = "", pos; switch(style){ case "linear": case "reflected": tempStops = style === "reflected" ? tools.reflectStops(stops) : stops; if (this.gradientDirections[angle]) { pos = this.gradientDirections[angle]; } else { pos = angle+"deg"; } if(pos == "to bottom"){ cssString = 'linear-gradient('+ tools.decodeStops(tempStops).join(", ") +')'; } else { cssString = 'linear-gradient('+ pos +', '+ tools.decodeStops(tempStops).join(", ") +')'; } break; case "contain": cssString = 'radial-gradient(center center, '+shape+'contain, '+ tools.decodeStops(stops).join(", ") +')'; break; case "cover": cssString = 'radial-gradient(center center, '+shape+'cover, '+ tools.decodeStops(stops).join(", ") +')'; break; } return cssString; }, drawGradient: function(style){ var cssString = "", model = style.background, tempAngle, tempOpacity, tempStops; if(model.isActive) { tempAngle = model.angle+180; if(tempAngle >= 360) tempAngle -= 360; tempOpacity = model.opacity; if(tempOpacity != 100){ tempOpacity = model.opacity/100; } if(!model.translucidStops) model.translucidStops = $.extend(true, [], model.stops); // inject opacity into the rgb values or slice off the injection if opacity is 100 for(var i=0, l=model.translucidStops.length; i') .css({ 'left': position+'%' }) .bind({ mousedown: $.proxy( this, "select" ), dblclick: $.proxy( this, "pick" ) }) .append($('
')) .append($('
') .append($('
').css({ 'background': tools.toColor(color) })) ); }, select: function(){ // fire "unselect" event // show middlepoints // add active class to this one // show color and position below // add pick event listener to the colorField // add event listener to the input field to update the position // add event listener on "unselect" to unselect }, blur: function(){ // remove active class // hide middle points // remove "unselect" listener }, pick: function(){ colorpicker.pick(this.color, this.updateColor, this); }, updateColor: function(newColor){ var colorString = color.toColor(newColor); this.color = newColor; this.$stopColor.css("background", colorString); this.$colorField.css("background", colorString); // add color to stops }, updatePosition: function(newPos){ this.position = newPos; // update position at stops } }, middlepoint: { threshhold: 5, position: null, percentage: null, init: function(position, percentage){ this.position = position; this.percentage = percentage; this.$el = this.create(); return this.$el; }, create: function(){ return $('') .attr({ 'data-percentage': this.percentage, }) .css({ 'left': this.position+'%' }) .bind(mousedown, $.proxy( this, "startMoving" )); }, startMoving: function(event){ event.preventDefault(); this.select(); gradienteditor.gradientOffset = gradienteditor.$gradient.offset(); $(document).bind('mousemove.global', $.proxy(this, "move") ); // add event listener to listen to input field changes // show percentage in the input field }, move: function(event){ // stay in the range of the previous and following step +/- 5 (min 5, max 95) // if position is 55-65 round to 50 // update input field value }, show: function(){ this.$el.addClass('visible'); }, hide: function(){ this.$el.removeClass('visible'); }, select: function(){ this.$el.addClass('selected'); }, unselect: function(){ this.$el.removeClass('selected'); } }, addPicker: function(position, rgb){ return $('
') .css({ 'left': position+'%' }) .attr({ 'data-color': JSON.stringify(rgb), 'data-percentage': position }) .bind({ mousedown: $.proxy( this, "selectPicker" ), dblclick: $.proxy( this, "startPicking" ) }) .append($('
')) .append($('
') .append($('
').css({ 'background': tools.toColor(rgb) })) ); }, selectPicker: function(event){ event.preventDefault(); var obj = $(event.target).parents('.picker'); this.selectStop(obj); this.showMiddlepoints(obj); this.gradientOffset = this.$gradient.offset(); this.extract(); $(document).bind('mousemove.global', $.proxy(this, "movePicker") ); $(document).one('mouseup', $.proxy(this, "stopPicking") ); }, startPicking: function(event){ event.preventDefault(); colorpicker.pick(this.currentStopColor, this.updatePicker, this); }, stopPicking: function(){ if(this.changed){ this.currentPick.attr('data-percentage', this.currentPercentage); } }, extract: function(){ this.tempStops = this.expand( $.extend(true, [], this.currentGradient.stops) ); this.tempStops.splice(this.currentPosition,1); }, inject: function(percentage){ if(this._percentage === undefined || percentage !== this._percentage){ var injectedStops = $.extend(true, [], this.tempStops), pos = injectedStops.length, stop = [this.currentStopColor, percentage]; for(var i = 0, l = injectedStops.length; i percentage){ pos = i; break; } } injectedStops.splice(pos, 0, stop); this.updateGradient( this.shrink(injectedStops) ); this._percentage = percentage; } }, expand: function(stops){ var last = stops.length-1; if(stops[0].length === 3) stops[0] = [stops[0], 0]; if(stops[last].length === 3) stops[last] = [stops[last], 100]; return stops; }, shrink: function(stops){ var last = stops.length-1; if(stops[0][1] === 0) stops[0] = stops[0][0]; if(stops[last][1] === 100) stops[last] = stops[last][0]; return stops; }, getArrayPos: function(percentage, stops){ for(var i = 0, l = stops.length; i (this.gradientOffset.left + this.gradientDimensions.width + 26) || event.pageY < (this.gradientOffset.top - 26) || event.pageY > (this.gradientOffset.top + this.gradientDimensions.height + 69) ){ // more than 2 color stops if(!this._hasMinimumSize){ x = event.pageX - this.gradientOffset.left; y = event.pageY - this.gradientOffset.top; if (this.puff === null) { this.puff = $('
').appendTo($body); $(document).bind('mouseup.puff', $.proxy( this, "removeCurrentPicker" )); } this.puff.css({ 'left': event.pageX+2, 'top': event.pageY+16 }); this.updateGradient( this.shrink(this.tempStops) ); } } else { // move picker this.currentPercentage = percentage; this.$stopLocation.val(percentage); this.inject(percentage); if(!this.changed){ this.$gradientName.val(lang.Custom); this.changed = true; }; if(this.puff != null){ $(document).unbind('mouseup.puff'); $('#puff').remove(); this.puff = null; } } $(this.currentPick).css({ 'left': x+'px', 'top': y+'px' }); }, removeCurrentPicker: function(event){ this.puff = null; $('#puff').remove(); $(this).unbind(event); }, updatePicker: function(newColor){ var colorString, stops; // newColor RGB-{Array} if(!this.changed){ this.$gradientName.val(lang.Custom); this.changed = true; }; colorString = tools.toColor(newColor); $(this.currentPick).attr('data-color', JSON.stringify(newColor)); this.currentColorField.css("background", colorString); this.$stopColor.css("background", colorString); stops = gradienteditor.currentGradient.stops; // search for the position and inject new color if(this.currentPosition > 0 && this.currentPosition < stops.length-1){ stops[this.currentPosition][1] = newColor; } else { stops[this.currentPosition] = newColor; } this.updateGradient(stops); }, addMiddlepoint: function(position, realpos){ return $('') .attr({ 'data-percentage': realpos, }) .css({ 'left': position+'%' }) .bind({ mousedown: function(e){ gradienteditor.selectStop(this); //gradienteditor.selectMiddlePoint(this); } }); }, updateGradient: function(stops){ gradienteditor.currentGradient.stops = stops; this.$gradient.css('background', css.cssGradient( stops, 0, "linear" )); if(gradienteditor.callback) gradienteditor.callback.call(gradienteditor.thisArg, stops); }, setGradient: function(gradient){ this.hideStop(); this.currentGradient = $.extend(true, [], gradient); this.$gradient.css('background', css.cssGradient( this.currentGradient.stops, 0, "linear" )); this.$gradientName.val(this.currentGradient.name); this.$gradient.children().remove(); var helpers = $('
'); for(var i=0,length = this.currentGradient.stops.length; i [255,255,255] or [[255,255,255], 33] if(stop.length === 3){ // => [255,255,255] color = stop; pos = i === 0 ? 0 : 100; } else { color = stop[0]; pos = stop[1]; } helpers.append( this.addPicker(pos, color) ); if(typeof this.currentGradient.stops[i+1] !== 'number' && i != length-1){ var nextStop = this.currentGradient.stops[i+1]; var nextPos = nextStop.length !== 3 ? nextStop[1] : 100; helpers.append( this.addMiddlepoint(tools.getCenter(pos, nextPos), 50) ); } break; case 'number': var middlepoint = tools.getMiddlepoint(this.currentGradient.stops[i-1], stop, this.currentGradient.stops[i+1]); helpers.append( this.addMiddlepoint(middlepoint[1], middlepoint[1]) ); break; } } this.$gradient.append(helpers); }, addGradientPreset: function(name, stops){ var preset = $('
') .attr({'title': name}) .css({ 'background': css.cssGradient( stops, 135, "linear" ) }) .bind('click', $.proxy( this, "handlePreset" )) return preset.get(0); }, handlePreset: function(e){ e.stopPropagation(); // find out the gradients position in the gradient array var family = $(e.target).parent().children(); var pos = family.index(e.target); // if alt is pressed while clicking: remove gradient if(e.altKey){ // slice out the gradient from the gradient array (method by John Resig) var rest = this.gradients.slice(pos + 1); this.gradients.length = pos; this.gradients.push.apply(this.gradients, rest); localStorage["gradients"] = JSON.stringify(this.gradients); $(e.target).remove(); } else { // else get the gradient this.setGradient(this.gradients[pos]); this.updateGradient(this.gradients[pos].stops); } }, showStop: function(pos, color){ this.$stopLocation.prop("disabled", false).val(pos).parent().removeClass("disabled"); if (color !== null) { if(!this._hasMinimumSize) this.$removeStop.prop("disabled", false); this.$stopColor.css({'background-color': color}).parent().removeClass("disabled"); this.$stopColor.bind('mousedown', $.proxy( this, "startPicking" )); } else { this.$removeStop.prop("disabled", true); this.$stopColor.css({'background-color': 'transparent'}).parent().addClass("disabled"); } }, updateStopColor: function(color){ this.$stopColor.css({'background-color': color}); }, hideStop: function(){ this.$removeStop.prop("disabled", true); this.$stopLocation.prop("disabled", true).val("").parent().addClass("disabled"); this.$stopColor.css({'background-color': 'transparent'}).parent().addClass("disabled"); }, selectStop: function(object){ var $o = $(object), color; this.currentPick = $o; this.currentPercentage = parseInt($o.attr('data-percentage'), 10); this.currentPosition = this.getArrayPos(this.currentPercentage, this.currentGradient.stops); this.currentColorField = $o.find('.color_field'); color = $o.attr('data-color'); this.currentStopColor = color ? JSON.parse(color) : null; this._hasMinimumSize = this.currentGradient.stops.length == 2 ? true : false; this.showStop(this.currentPercentage, this.currentStopColor); $o.siblings().removeClass('selected'); $o.addClass('selected'); }, showMiddlepoints: function(object){ $(object).siblings('span').removeClass('visible'); $(object).next('span').add($(object).prev('span')).addClass('visible'); }, cancelAction: function(){ gradienteditor.updateGradient(gradienteditor.prevStops); nav.goTo(1); }, okAction: function(){ nav.goTo(1); }, newAction: function(){ if(this.changed){ var newGradient = { 'name': this.$gradientName.val(), 'stops': this.currentGradient.stops }; this.gradients.push(newGradient); this.renderPresets([newGradient]); localStorage["gradients"] = JSON.stringify(this.gradients); this.changed = false; }; }, renderPresets: function(gradients){ var presets = document.createDocumentFragment(); for(var i = 0, length = gradients.length; i= 96 && keycode <= 105){ character = numbers.numpadKeys[keycode]; } else { character = String.fromCharCode(keycode); } if(numbers.commandKeyPressed){ isCopyCutPasteKey = numbers.copyCutPasteKeys.join(",").match(new RegExp(keycode)); if(isCopyCutPasteKey){ return true; } } if(keycode === 91) { numbers.commandKeyPressed = true; return false; } // 1 for key up (keycode 38), -1 for key down (keycode 40), 0 for other keys numbers.direction = 0; switch(keycode){ case 38: numbers.direction = 1; break; case 40: numbers.direction = -1; break; } if (numbers.direction !== 0 && numbers.restrict === numbers.DIGITS) { numbers.accelerate(); return false; } else { isControlKey = numbers.controlKeys.join(",").match(new RegExp(keycode)); if (isControlKey) { return true; } else if (character.match(numbers.restrict)) { numbers.value += character; return true; } event.preventDefault(); return false; } }, accelerate: function() { if(numbers.timeout) clearTimeout(numbers.timeout); if(numbers.value === '') { numbers.value = 0; } var number = parseInt(numbers.value, 10); number += numbers.direction; number = Math.max(numbers.min, Math.min(numbers.max, number)); if('-'+numbers.max === numbers.min) { // as in angle from -180 to 180 if(number === numbers.min) number = numbers.max; else if(number === numbers.max) number = numbers.min; } numbers.$input.val(number); numbers.value = number; numbers.updateField(); if(!numbers.pressed){ numbers.speed = 500; numbers.pressed = true; } else { numbers.speed = 150; } numbers.timeout = setTimeout(function(){ jQuery.proxy(numbers, "accelerate") }, numbers.speed); }, validateInput: function(event) { var integer, errorString, nearestInt; numbers.value = numbers.$input.val(); integer = parseInt(numbers.value, 10); if(numbers.regex.test(integer)){ console.log(integer); numbers.$input.val(integer ? integer : ""); return true; } event.preventDefault(); errorString = lang.AnIntegerBetween+" "+ numbers.min +" "+lang.and+" "+ numbers.max +" "+lang.isRequired+". "+lang.ClosestValueInserted+"."; alert(errorString); nearestInt = Math.abs(numbers.max - integer) < Math.abs(numbers.min - integer) ? numbers.max : numbers.min; numbers.$input.val(nearestInt).focus().change(); } }; ================================================ FILE: js/style.js ================================================ var style = { background: { elements: { ".opacity": { name: "opacity", handle: "slider" }, ".gradientField": "gradientField", ".reverse": "reverse", ".angle": { name: "angle", handle: "pot" }, ".globalLight": "globalLight" }, $styles: $('#background_style'), init: function(el){ this.$el = $("#"+el); this.selector = el; this.$menuItem = $('.nav-'+el); this.$checkbox = this.$menuItem.find('input[type=checkbox]'); this.$inputs = this.$el.find('input[type=text]'); this.initElements(); this.updateStops(); this.$gradientField.click( $.proxy( this, "edit" ) ); this.$reverse.change( $.proxy( this, "switchReverse" ) ); this.$globalLight.click( $.proxy( this, "switchLight" ) ); this.$checkbox.click( $.proxy( this, "check" ) ); this.$menuItem.click( $.proxy( this, "select" ) ); this.$styles.change( $.proxy( this, "updateStyle" ) ); $(document).bind('styleChange', $.proxy( this, "populateInputs" )); }, initElements: function(){ for (var key in this.elements) { var el = this.elements[key]; if(typeof el === 'object'){ this["$"+el.name] = $(key, this.$el); switch(el.handle){ case "slider": this[el.name+"Slider"] = Object.create(slider); this[el.name+"Slider"].init(this.selector, el.name); break; case "pot": this[el.name+"Pot"] = Object.create(pot); this[el.name+"Pot"].init(this.selector); break; } } else { this["$"+el] = $(key, this.$el); } } }, populateInputs: function(){ this.setActive(); this.opacitySlider.update(currentStyle[this.selector].opacity); this.updateStops(); this.setReverse(); this.displayStyle(); this.setLight(); }, select: function(){ if(!currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = true; this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); this.paint(); } }, check: function(e){ e.stopPropagation(); if(currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = false; } else { currentStyle[this.selector].isActive = true; } this.setActive(); this.paint(); }, setActive: function(){ if(currentStyle[this.selector].isActive){ this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); } else { this.$checkbox.prop('checked', false); this.$el.addClass('inactive'); this.$inputs.prop('disabled', true); } }, edit: function(){ gradienteditor.edit(currentStyle[this.selector].stops, this.updateStops, this); }, setReverse: function(){ if(currentStyle[this.selector].isReverse){ this.$reverse.prop('checked', true); } else { this.$reverse.prop('checked', false); } this.updateStops(); this.paint(); }, switchReverse: function(){ if(currentStyle[this.selector].isReverse){ currentStyle[this.selector].isReverse = false; } else { currentStyle[this.selector].isReverse = true; } this.setReverse(); }, setLight: function(){ if(currentStyle[this.selector].hasGlobalLight){ this.$globalLight.prop('checked', true); this.anglePot.update(currentStyle.globalAngle); } else { this.$globalLight.prop('checked', false); this.anglePot.update(currentStyle[this.selector].angle); } }, switchLight: function(){ if(currentStyle[this.selector].hasGlobalLight){ currentStyle[this.selector].hasGlobalLight = false; } else { currentStyle[this.selector].hasGlobalLight = true; } this.setLight(); this.paint(); }, updateStyle: function(){ currentStyle[this.selector].style = this.$styles.val(); this.paint(); }, displayStyle: function(){ this.$styles.val(currentStyle[this.selector].style); }, updateStops: function(stops){ if(stops){ currentStyle[this.selector].stops = stops; currentStyle[this.selector].translucidStops = $.extend(true, [], stops); this.paint(); } this.$gradientField.css('background', css.cssGradient( currentStyle[this.selector].stops, currentStyle[this.selector].isReverse ? 180 : 0, "linear" )); }, paint: function(){ $(document).trigger('paint'); } }, shadow: { elements: { ".opacity": { name: "opacity", handle: "slider" }, ".color_field": "color", ".angle": { name: "angle", handle: "pot" }, ".globalLight": "globalLight", ".distance": { name: "distance", handle: "slider" }, ".blur": { name: "blur", handle: "slider" }, ".size": { name: "size", handle: "slider" } }, init: function(el){ this.$el = $("#"+el); this.selector = el; this.$menuItem = $('.nav-'+el); this.$checkbox = this.$menuItem.find('input[type=checkbox]'); this.$inputs = this.$el.find('input[type=text]'); this.initElements(); this.updateColor(); this.$color.click( $.proxy( this, "pick" ) ); this.$checkbox.click( $.proxy( this, "check" ) ); this.$menuItem.click( $.proxy( this, "select" ) ); this.$globalLight.click( $.proxy( this, "switchLight" ) ); $(document).bind('styleChange', $.proxy( this, "populateInputs" )); }, initElements: function(){ for (var key in this.elements) { var el = this.elements[key]; if(typeof el === 'object'){ this["$"+el.name] = $(key, this.$el); switch(el.handle){ case "slider": this[el.name+"Slider"] = Object.create(slider); this[el.name+"Slider"].init(this.selector, el.name); //if(el.autoUpdate) currentStyle[this.selector].__defineSetter__( el.name , $.proxy( this[el.name+"Slider"], "set" ) ); break; case "pot": this[el.name+"Pot"] = Object.create(pot); this[el.name+"Pot"].init(this.selector); break; } } else { this["$"+el] = $(key, this.$el); } } }, populateInputs: function(){ this.setActive(); this.updateColor(); this.opacitySlider.update(currentStyle[this.selector].opacity); this.distanceSlider.update(currentStyle[this.selector].distance); this.blurSlider.update(currentStyle[this.selector].blur); this.sizeSlider.update(currentStyle[this.selector].size); this.setLight(); }, select: function(){ if(!currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = true; this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); this.paint(); } }, check: function(e){ e.stopPropagation(); if(currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = false; } else { currentStyle[this.selector].isActive = true; } this.setActive(); this.paint(); }, setActive: function(){ if(currentStyle[this.selector].isActive){ this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); } else { this.$checkbox.prop('checked', false); this.$el.addClass('inactive'); this.$inputs.prop('disabled', true); } }, pick: function(){ colorpicker.pick(currentStyle[this.selector].color, this.updateColor, this); }, setLight: function(){ if(currentStyle[this.selector].hasGlobalLight){ this.$globalLight.prop('checked', true); this.anglePot.update(currentStyle.globalAngle); } else { this.$globalLight.prop('checked', false); this.anglePot.update(currentStyle[this.selector].angle); } }, switchLight: function(){ if(currentStyle[this.selector].hasGlobalLight){ currentStyle[this.selector].hasGlobalLight = false; } else { currentStyle[this.selector].hasGlobalLight = true; } this.setLight(); this.paint(); }, updateColor: function(currentColor){ if(currentColor){ currentStyle[this.selector].color = currentColor; this.paint(); } this.$color.css('background', '#'+color.hexFromRgb(currentStyle[this.selector].color)); }, paint: function(){ $(document).trigger('paint'); } }, border: { elements: { ".color_field": "color", ".opacity": { name: "opacity", handle: "slider" }, ".size": { name: "size", handle: "slider" } }, $styles: $('#border_styles').find('> div'), init: function(el){ this.$el = $("#"+el); this.selector = el; this.$menuItem = $('.nav-'+el); this.$checkbox = this.$menuItem.find('input[type=checkbox]'); this.$inputs = this.$el.find('input[type=text]'); this.initElements(); this.updateColor(); this.$color.click( $.proxy( this, "pick" ) ); this.$checkbox.click( $.proxy( this, "check" ) ); this.$menuItem.click( $.proxy( this, "select" ) ); this.$styles.click( $.proxy( this, "updateStyle" ) ); $(document).bind('styleChange', $.proxy( this, "populateInputs" )); }, initElements: function(){ for (var key in this.elements) { var el = this.elements[key]; if(typeof el === 'object'){ this["$"+el.name] = $(key, this.$el); switch(el.handle){ case "slider": this[el.name+"Slider"] = Object.create(slider); this[el.name+"Slider"].init(this.selector, el.name); break; case "pot": this[el.name+"Pot"] = Object.create(pot); this[el.name+"Pot"].init(this.selector); break; } } else { this["$"+el] = $(key, this.$el); } } }, populateInputs: function(){ this.setActive(); this.updateColor(); this.opacitySlider.update(currentStyle[this.selector].opacity); this.sizeSlider.update(currentStyle[this.selector].size); this.setStyle(); }, select: function(){ if(!currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = true; this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); this.paint(); } }, check: function(e){ e.stopPropagation(); if(currentStyle[this.selector].isActive){ currentStyle[this.selector].isActive = false; } else { currentStyle[this.selector].isActive = true; } this.setActive(); this.paint(); }, setActive: function(){ if(currentStyle[this.selector].isActive){ this.$checkbox.prop('checked', true); this.$el.removeClass('inactive'); this.$inputs.prop('disabled', false); } else { this.$checkbox.prop('checked', false); this.$el.addClass('inactive'); this.$inputs.prop('disabled', true); } }, pick: function(){ colorpicker.pick(currentStyle[this.selector].color, this.updateColor, this); }, setStyle: function(){ for(var i=0, l=this.$styles.length; i') .attr({ 'title': name, 'data-pos': pos }) .bind('mousedown', { self : this }, styleStore.select ) .append( $('
').css(cssObj) ); return swatch.get(0); }, select: function(e){ e.stopPropagation(); var self = e.data.self; var $obj = $(this); var family = $obj.parent().children(); var pos = family.index(this); // if alt is pressed while clicking: remove style if(e.altKey){ // double check - styles are precious if(pos !== 0 && window.confirm( lang.DeleteStyle + ' "'+ self.styles[pos].name +'"?' )){ // slice out the gradient from the gradient array (method by John Resig) var rest = self.styles.slice(pos + 1); self.styles.length = pos; self.styles.push.apply(self.styles, rest); localStorage["styles"] = JSON.stringify(self.styles); $obj.remove(); } } else { // else set the style family.removeClass('active'); self.loadStyle(pos); } }, compress: function(style){ var slimStyle = {}; var fatStyle = $.extend(true, {}, style); for( key in fatStyle ){ var value = fatStyle[key]; if(typeof style === "object"){ if(value.isActive){ slimStyle[key] = {}; for( prop in value ){ var propVal = value[prop]; if( defaults[key][prop] === undefined ) continue; if( typeof propVal === "object" ){ if( !jQuery.compare(propVal, defaults[key][prop]) ){ slimStyle[key][prop] = propVal; } } else if( propVal != defaults[key][prop] && prop !== "isActive" ){ slimStyle[key][prop] = propVal; } } if( jQuery.isEmptyObject(slimStyle[key]) ) delete slimStyle[key]; } else { if(defaults[key].isActive){ slimStyle[key] = { isActive: false }; } } } else if(key === "globalAngle" && value !== defaults.globalAngle){ slimStyle["globalAngle"] = value; } } return slimStyle; }, decompress: function(packedStyle){ var expandedStyle = $.extend(true, {}, defaults); for(key in packedStyle){ expandedStyle[key] = $.extend({}, defaults[key], packedStyle[key]); if(packedStyle[key].isActive !== undefined){ expandedStyle[key].isActive = packedStyle[key].isActive; } else { expandedStyle[key].isActive = true; } } return expandedStyle; }, loadStyle: function(pos){ this.$el.children().eq(pos).addClass('active'); currentStyle = this.decompress(this.styles[pos].style); $(document).trigger('styleChange').trigger('paint'); }, create: function(){ var newStyle, name = prompt(lang.NewStyle,"Style "+this.styles.length); if(name){ newStyle = {'name': name, 'style': this.compress(currentStyle)}; this.styles.push(newStyle); this.renderStyles([newStyle]); localStorage["styles"] = JSON.stringify(this.styles); } } } ================================================ FILE: js/tools.js ================================================ var tools = { options: { hex: true }, /** * @method averageGradientColor * @param fullStops {stops-array} * @return color {string} * @example averageGradientColor([[255,255,255], [0,0,0]]) returns gray */ averageGradientColor: function(fullStops){ var stops = gradienteditor.expand( $.extend(true, [], fullStops) ), reducedArray = [], l = stops.length; for(var i = 0; i < l; i++){ var stop = stops[i]; if(typeof stop === 'number'){ stops[i] = this.getMiddlepoint(stops[i-1], stop, stops[i+1]); } } for(var i = 0; i < l-1; i++){ var stopA = stops[i], stopB = stops[i+1]; reducedArray.push(this.averageStop(stopA, stopB)); } // reduce array to one rgb array reducedArray = reducedArray.reduce(this.averageColor, [0,0,0]); // round its values for(var i=0; i<3; i++){ reducedArray[i] = Math.round(reducedArray[i]); } // return said array as color string return this.toColor(reducedArray); }, /** * @method averageStop * @param stopA {stop-array} * @param stopB {stop-array} * @return color-stop {stop-array} * @example averageStop([[255,255,255], 0], [[0,0,0], 100]) returns [[128,128,128], 50] */ averageStop: function(stopA, stopB){ var colorA = stopA[0], posA = stopA[1], colorB = stopB[0], posB = stopB[1]; return [ [ this.getCenter(colorA[0],colorB[0]), this.getCenter(colorA[1],colorB[1]), this.getCenter(colorA[2],colorB[2]) ], posB - posA ]; }, /** * @method averageColor * @param previousValue {color-array} * @param currentValue {stop-array} * @return color {color-array} */ averageColor: function(previousValue, currentValue, index, array){ var color = currentValue[0], weight = currentValue[1]/100; return [ previousValue[0] + color[0] * weight, // r previousValue[1] + color[1] * weight, // g previousValue[2] + color[2] * weight // b ]; }, /** * @method roundToMultiple * @param number {integer} * @param multiple {integer} multiple to round to * @return rounded number {integer} * @example roundToMultiple(35, 15) returns 30 * @usage in ui.js -> pot; to round to 15° steps */ roundToMultiple: function(number, multiple){ var value = number/multiple, integer = Math.floor(value), rest = value - integer; return rest > 0.5 ? (integer+1)*multiple : integer*multiple; }, /** * @method toColor * @param rgb {array} RGB or RGBA Color Array * @return CSS Color {string} * @example toColor([255,255,255]) returns 'rgb(255,255,255)' * toColor([255,255,255,0.5]) returns 'rgba(255,255,255,0.5)' */ toColor: function(rgb){ var mode = rgb.length === 3 ? 'rgb' : 'rgba', string = mode+'('+rgb.join(',')+')'; if (css.colors[string]) { return css.colors[string]; } else if(this.options.hex && mode === 'rgb'){ return "#"+color.hexFromRgb(rgb); } return string; }, /** * @method getCenter returns the center between a starting and an ending point * @param start {integer} * end {integer} * offset {integer} [optional] if the center has an offset * @return center {integer} * @example getCenter(0, 60) returns 30 * getCenter(0, 60, 75) returns 45 */ getCenter: function(start, end, offset){ var o = offset || 50; return start + Math.round(o/100*(end-start)); }, /** * @method getMiddlepoint returns the color at a specific position on a color gradient defined through a start and end color * @param start {array} eiter a rgb color (like [255,255,255])or a rgb color and a positon (e.g. [[255,255,255], 10]) * pos {integer} position * end {array} rgb color [r, g, b] * @return {array} of the rgb color {array} and relative index {integer} * @example getCenter(0, 60) returns 30 * getCenter(0, 60, 75) returns 45 */ getMiddlepoint: function(start, pos, end){ var startColor = start, endColor = end, startIndex = 0, endIndex = 100, index = 0, color = []; if(start.length === 2){ startIndex = start[1]; startColor = start[0]; } if(end.length === 2){ endIndex = end[1]; endColor = end[0]; } index = this.getCenter(startIndex, endIndex, pos); for (var i=0, l = startColor.length; i [255,255,255] or [[255,255,255], 33] if(stop.length > 2){ // => [255,255,255] steps[i] = this.toColor(stop); } else { // => [[255,255,255], 33] steps[i] = this.toColor(stop[0])+" "+stop[1]+"%"; } break; case 'number': // => 11 var middlepoint = this.getMiddlepoint(stops[i-1], stop, stops[i+1]); steps[i] = this.toColor(middlepoint[0])+" "+middlepoint[1]+"%"; break; } } return steps; }, /** * @method decodeCanvasGradient * @param stops {array} the color stops * @param angle {integer} the gradients angle * @param ctx {canvas 2d context} the context the gradient is for * @param x {integer} the x coordinate where the gradient should start * @param y {integer} the y coordinate where the gradient should start * @param width {integer} the width of the gradients box * @param height {integer} the height of the gradients box * @return {canvas-gradient} */ decodeCanvasGradient: function(stops, angle, style, ctx, x, y, width, height){ var gradient, // looks like stops is still referenced to currentStyle.background.translucentStops at this point tempStops = $.extend(true, [], stops); switch(style){ case "linear": /* missing: angle support 0° -> x+width, y, x, y 45° -> x+width, y, x, y+height 90° -> x, y, x, y+height 135°-> x, y, x+width, y+height 180°-> x, y, x+width, y 225°-> x, y+height, x+width, y 270°-> x, y+height, x, y 315°-> x+width, y+height, x, y there is a pattern :) something with sin & cos for now now default to 90 */ gradient = ctx.createLinearGradient(x, y, x, y+height); break; case "reflected": tempStops = this.reflectStops(tempStops); gradient = ctx.createLinearGradient(x, y, x, y+height); break; case "contain": var closestSide = width < height ? width/2 : height/2; gradient = ctx.createRadialGradient(x+width/2, y+height/2, 0, x+width/2, y+height/2, closestSide); // centered break; case "cover": // farest corner = half diagonal side >> pitagoras var farestCorner = Math.sqrt( width * width + height * height )/2; gradient = ctx.createRadialGradient(x+width/2, y+height/2, 0, x+width/2, y+height/2, farestCorner); // centered break; } // bring the stops in the right order for canvas gradient: for(var i=0, length=tempStops.length; i [255,255,255] or [[255,255,255], 33] if(stop.length === 3){ // => [255,255,255] pos = i === 0 ? 0 : 100; // can either be the start or the end color = this.toColor(stop); } else { // => [[255,255,255], 33] color = this.toColor(stop[0]); pos = stop[1]; } break; case 'number': // => 11 var middlepoint = this.getMiddlepoint(tempStops[i-1], stop, tempStops[i+1]); color = this.toColor(middlepoint[0]); pos = middlepoint[1]; break; } // pos is now between 0-100 - for canvas we need it between 0-1 pos = pos/100; pos = pos+''; // <-- to change from number to string seems to fix a bug in firefox on ubuntu gradient.addColorStop(pos, color); } return gradient; }, /** * @method opposite * @param direction {String} * @return {String} opposite direction * @example opposite('top') returns 'bottom' */ opposite: function(direction) { switch(direction){ case 'top': return 'bottom'; case 'right': return 'left'; case 'bottom': return 'top'; case 'left': return 'right'; } }, reflectStops: function(stops){ var first = [], second = []; // bug: turns everything around for(var i=0, l=stops.length; i div'); this.model = el; this.$el.bind("mousedown", $.proxy( this, "start" ) ); this.$input = this.$el.next('div').children('input:first-child'); this.$input.change( $.proxy( this, "get" ) ); }, start: function(event){ var myOffset = this.$el.offset(); this.offset = { x: myOffset.left+(this.width/2), y: myOffset.top+(this.height/2) }; this.turn(event); $(document).bind('mousemove.global', $.proxy( this, "turn") ); }, get: function(){ var value = parseInt(this.$input.val()); this.update(value); }, set: function(value){ this.$input.val(value); }, update: function(value){ this.move(value); if(currentStyle[this.model].hasGlobalLight) currentStyle.globalAngle = value; currentStyle[this.model].angle = value; this.set(value); style[this.model].paint(); }, move: function(degrees){ this.$pointer.css('transform', 'rotate('+-degrees+'deg)'); }, turn: function(event){ event.preventDefault(); var opposite = this.offset.y - event.pageY, adjacent = event.pageX - this.offset.x, radiants = Math.atan(opposite/adjacent), degrees = Math.round(radiants*(180/Math.PI), 10); if(event.shiftKey) degrees = tools.roundToMultiple(degrees, 15); if(adjacent < 0 && opposite >= 0){ degrees+= 180; } else if(opposite < 0 && adjacent < 0){ degrees-= 180; } if(degrees === -180) degrees = 180; this.update(degrees); } }; var toggle = { _treshhold: 2, _moving: false, init: function(el, toggle, thisArg, callback){ this.$el = $("#"+el); this.$slider = this.$el.find('.slidePanel'); this.width = this.$el.width(); this.toggle = toggle; this.model = thisArg; // render befor the callback gets asigned to not call the callback at init this.render(); this.callback = callback; this.$el.bind('mousedown', $.proxy( this, "start" ) ); }, start: function(event){ event.preventDefault(); this._startPos = event.pageX - this.$el.offset().left; this.$el.addClass('down'); $(document).bind('mousemove.global', $.proxy( this, "move") ); $(document).one('mouseup', $.proxy( this, "stop") ); }, move: function(event){ var distance = event.pageX - this._startPos; if(!this._moving && Math.abs(distance) > this._treshhold){ this.$el.addClass('moving'); this._moving = true; } if(this._moving){ this._pos = Math.min(0, Math.max(-this.width/2, this._offset + distance)); this.$slider.css('left', this._pos); } }, render: function(){ this._offset = this.model[this.toggle] ? -this.width/2 : 0; this.$slider.css('left', this._offset); if(this.callback) this.callback(); }, stop: function(event){ this.$el.removeClass('down'); if(this._moving){ this._moving = false; this.$el.removeClass('moving'); if(this._pos >= -this.width/4){ this.model[this.toggle] = false; } else { this.model[this.toggle] = true; } } else { this.model[this.toggle] = !this.model[this.toggle]; } this.render(); } }; var slider = { init: function(el, model){ this.$el = $("#"+el+" ."+model).prev("div.slider"); this.$pointer = this.$el.find('> div:nth-child(2)'); this.$input = this.$el.next('input'); this.max = this.$input.data("max"); this.length = this.$el.width(); this.ease = this.$el.data("easing"); this.style = el; this.model = model; this.$el.bind("mousedown", $.proxy( this, "start" ) ); this.$input.change( $.proxy( this, "get" ) ); }, acc: function(x){ return this.ease ? x*x : x; }, invAcc: function(x){ return this.ease ? Math.sqrt(x) : x; }, get: function(){ var value = parseInt(this.$input.val()); this.update(value); }, set: function(value){ this.$input.val(value); }, update: function(value, position){ this.move(this.toPos(value)); currentStyle[this.style][this.model] = value; this.move(position || this.toPos(value)); this.set(value); style[this.style].paint(); }, move: function(x){ this.$pointer.css({ left: x+'px' }); }, toPos: function(value){ var percentage = this.invAcc(value/this.max); return Math.round(this.length*percentage); }, toValue: function(position){ var percentage = this.acc(position/this.length); return Math.round(percentage*this.max); }, start: function(event){ this.offset = { x: this.$el.offset().left }; this.slide(event); $(document).bind('mousemove.global', $.proxy( this, "slide" ) ); }, slide: function(event){ event.preventDefault(); var value, position = Math.max(0, Math.min(this.length, event.pageX - this.offset.x)); value = this.toValue(position); this.update(value, position); } }; ================================================ FILE: js/universe.js ================================================ var parallelUniverse = { x: 0, y: 0, KAPPA: 4*(Math.SQRT2-1)/3, roundToHalf: function(value){ // makes the borders crisp return (value - parseInt(value, 10)) === 0.5 ? value+1 : value + 1.5; }, draw: function(){ this.x = this.roundToHalf(dimensions.width/2 - currentStyle.width/2); this.y = this.roundToHalf(dimensions.height/2 - currentStyle.height/2); pu.clearRect(0,0,dimensions.width,dimensions.height); this.background(); this.drawCanvases(); this.shadow(); pu.beginPath(); this.rect(pu); pu.closePath(); this.layerBackground(); this.innerShadow(); this.border(); }, background: function(){ pu.fillStyle = tools.decodeCanvasGradient( background.background[1].stops, background.background[1].angle, background.background[1].style, pu, 0, 0, dimensions.width, dimensions.height ); pu.fillRect(0, 0, dimensions.width, dimensions.height); }, rect: function(ctx){ var br = currentStyle.borderRadius; if(br.isActive){ for(var i=3; i>=0; i--){ var radiusX, radiusY, unit, percentage; unit = br.radii[i][1]; if(unit === "%"){ percentage = Math.min(0.5, br.radii[i][0]/100); radiusY = percentage*currentStyle.height; radiusX = percentage*currentStyle.width; } else { radiusX = radiusY = Math.min(currentStyle.width/2, br.radii[i][0]); } switch(i){ // anti-clockwise because of the innerShadow-mask case 3: // start at left middle; then bottom left ctx.moveTo(this.x, this.y+currentStyle.height/2); ctx.lineTo(this.x, this.y+currentStyle.height-radiusY); ctx.bezierCurveTo(this.x, this.y+currentStyle.height-radiusY+radiusY*this.KAPPA, this.x+(radiusX-radiusX*this.KAPPA), this.y+currentStyle.height, this.x+radiusX, this.y+currentStyle.height); break; case 2: // upper right ctx.lineTo(this.x+currentStyle.width-radiusX, this.y+currentStyle.height); ctx.bezierCurveTo(this.x+currentStyle.width-radiusX+radiusX*this.KAPPA, this.y+currentStyle.height, this.x+currentStyle.width, this.y+currentStyle.height-radiusY+radiusY*this.KAPPA, this.x+currentStyle.width, this.y+currentStyle.height-radiusY); break; case 1: // bottom right ctx.lineTo(this.x+currentStyle.width, this.y+radiusY); ctx.bezierCurveTo(this.x+currentStyle.width, this.y+(radiusY-radiusY*this.KAPPA), this.x+currentStyle.width-radiusX+radiusX*this.KAPPA, this.y, this.x+currentStyle.width-radiusX, this.y); break; case 0: // upper left and then back to left middle; ctx.lineTo(this.x+radiusX, this.y); ctx.bezierCurveTo(this.x+(radiusX-radiusX*this.KAPPA), this.y, this.x, this.y+(radiusY-radiusY*this.KAPPA), this.x, this.y+radiusY); ctx.lineTo(this.x, this.y+currentStyle.height/2); break; } } } else { // outwritten rect anti-clockwise instead of the ctx.rect(x,y,width,height) because of the innerShadow mask ctx.moveTo(this.x, this.y); ctx.lineTo(this.x, this.y+currentStyle.height); ctx.lineTo(this.x+currentStyle.width, this.y+currentStyle.height); ctx.lineTo(this.x+currentStyle.width, this.y); ctx.lineTo(this.x, this.y); } }, drawCanvases: function(){ var $canvases = $workspace.find('canvas.moveable'); $.each($canvases, function(i, canvas){ var $canvas = $(canvas), offset = $canvas.offset(); pu.drawImage(canvas, offset.left, offset.top); }); }, shadow: function(){ var sd = currentStyle.dropShadow, dropColor; if(sd.isActive){ pu.save(); pu.beginPath(); this.rect(pu); dropColor = sd.color.slice(0); dropColor.push(sd.opacity/100); dropColor = tools.toColor(dropColor); pu.fillStyle = dropColor; pu.shadowOffsetX = sd.dropX; pu.shadowOffsetY = sd.dropY; pu.shadowBlur = sd.blur; pu.shadowColor = dropColor; pu.fill(); pu.closePath(); pu.restore(); } }, innerShadow: function(){ var is = currentStyle.innerShadow, dropColor; if(is.isActive){ iu.save(); iu.beginPath(); // draw the layer box as negativ area and use normal dropShadow in another universe // idea by Alistair MacDonald https://gist.github.com/787544 iu.rect(0,0,dimensions.width,dimensions.height); iu.moveTo(this.x, this.y); this.rect(iu); dropColor = is.color.slice(0); dropColor.push(is.opacity/100); dropColor = tools.toColor(dropColor); iu.shadowOffsetX = is.dropX; iu.shadowOffsetY = is.dropY; iu.shadowBlur = is.blur; iu.shadowColor = dropColor; iu.fill(); iu.closePath(); iu.restore(); // clip the paralell universe temporarily to the layers size (border-radius!) // and draw the inner shadow from the other universe to the main parallel Universe pu.save(); pu.beginPath(); this.rect(pu); pu.closePath(); pu.clip(); pu.drawImage($innerShadowUniverse.get(0), this.x, this.y, currentStyle.width, currentStyle.height, this.x, this.y, currentStyle.width, currentStyle.height); pu.restore(); iu.clearRect(0,0,dimensions.width,dimensions.height); } }, layerBackground: function(){ var bg = currentStyle.background, tempAngle, tempStops; if(bg.isActive) { tempAngle = bg.angle; tempStops = $.extend(true, [], bg.translucidStops); // no deep copy! if(bg.hasGlobalLight) bg.angle = currentStyle.globalAngle; if(bg.isReverse) tempStops = tools.reverseStops(tempStops); pu.fillStyle = tools.decodeCanvasGradient( tempStops, tempAngle, bg.style, pu, this.x, this.y, currentStyle.width, currentStyle.height ); pu.fill(); } }, border: function(){ var bd = currentStyle.border, borderColor; if(bd.isActive){ borderColor = bd.color.slice(0); borderColor.push(bd.opacity/100); pu.strokeStyle = tools.toColor(borderColor); pu.lineWidth = bd.size; pu.stroke(); } } }; ================================================ FILE: js/zeroclipboard/ZeroClipboard.as ================================================ package { // Simple Set Clipboard System // Author: Joseph Huckaby import flash.display.Stage; import flash.display.Sprite; import flash.display.LoaderInfo; import flash.display.StageScaleMode; import flash.events.*; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.external.ExternalInterface; import flash.system.Security; import flash.utils.*; import flash.system.System; public class ZeroClipboard extends Sprite { private var id:String = ''; private var button:Sprite; private var clipText:String = ''; public function ZeroClipboard() { // constructor, setup event listeners and external interfaces stage.scaleMode = StageScaleMode.EXACT_FIT; flash.system.Security.allowDomain("*"); // import flashvars var flashvars:Object = LoaderInfo( this.root.loaderInfo ).parameters; id = flashvars.id; // invisible button covers entire stage button = new Sprite(); button.buttonMode = true; button.useHandCursor = true; button.graphics.beginFill(0xCCFF00); button.graphics.drawRect(0, 0, Math.floor(flashvars.width), Math.floor(flashvars.height)); button.alpha = 0.0; addChild(button); button.addEventListener(MouseEvent.CLICK, clickHandler); button.addEventListener(MouseEvent.MOUSE_OVER, function(event:Event) { ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'mouseOver', null ); } ); button.addEventListener(MouseEvent.MOUSE_OUT, function(event:Event) { ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'mouseOut', null ); } ); button.addEventListener(MouseEvent.MOUSE_DOWN, function(event:Event) { ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'mouseDown', null ); } ); button.addEventListener(MouseEvent.MOUSE_UP, function(event:Event) { ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'mouseUp', null ); } ); // external functions ExternalInterface.addCallback("setHandCursor", setHandCursor); ExternalInterface.addCallback("setText", setText); // signal to the browser that we are ready ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'load', null ); } public function setText(newText) { // set the maximum number of files allowed clipText = newText; } public function setHandCursor(enabled:Boolean) { // control whether the hand cursor is shown on rollover (true) // or the default arrow cursor (false) button.useHandCursor = enabled; } private function clickHandler(event:Event):void { // user click copies text to clipboard // as of flash player 10, this MUST happen from an in-movie flash click event System.setClipboard( clipText ); ExternalInterface.call( 'ZeroClipboard.dispatch', id, 'complete', clipText ); } } } ================================================ FILE: js/zeroclipboard/ZeroClipboard.js ================================================ // Simple Set Clipboard System // Author: Joseph Huckaby var ZeroClipboard = { version: "1.0.7", clients: {}, // registered upload clients on page, indexed by id moviePath: 'ZeroClipboard.swf', // URL to movie nextId: 1, // ID of next movie $: function(thingy) { // simple DOM lookup utility function if (typeof(thingy) == 'string') thingy = document.getElementById(thingy); if (!thingy.addClass) { // extend element with a few useful methods thingy.hide = function() { this.style.display = 'none'; }; thingy.show = function() { this.style.display = ''; }; thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; }; thingy.removeClass = function(name) { var classes = this.className.split(/\s+/); var idx = -1; for (var k = 0; k < classes.length; k++) { if (classes[k] == name) { idx = k; k = classes.length; } } if (idx > -1) { classes.splice( idx, 1 ); this.className = classes.join(' '); } return this; }; thingy.hasClass = function(name) { return !!this.className.match( new RegExp("\\s*" + name + "\\s*") ); }; } return thingy; }, setMoviePath: function(path) { // set path to ZeroClipboard.swf this.moviePath = path; }, dispatch: function(id, eventName, args) { // receive event from flash movie, send to client var client = this.clients[id]; if (client) { client.receiveEvent(eventName, args); } }, register: function(id, client) { // register new client to receive events this.clients[id] = client; }, getDOMObjectPosition: function(obj, stopObj) { // get absolute coordinates for dom element var info = { left: 0, top: 0, width: obj.width ? obj.width : obj.offsetWidth, height: obj.height ? obj.height : obj.offsetHeight }; while (obj && (obj != stopObj)) { info.left += obj.offsetLeft; info.top += obj.offsetTop; obj = obj.offsetParent; } return info; }, Client: function(elem) { // constructor for new simple upload client this.handlers = {}; // unique ID this.id = ZeroClipboard.nextId++; this.movieId = 'ZeroClipboardMovie_' + this.id; // register client with singleton to receive flash events ZeroClipboard.register(this.id, this); // create movie if (elem) this.glue(elem); } }; ZeroClipboard.Client.prototype = { id: 0, // unique ID for us ready: false, // whether movie is ready to receive events or not movie: null, // reference to movie object clipText: '', // text to copy to clipboard handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor cssEffects: true, // enable CSS mouse effects on dom container handlers: null, // user event handlers glue: function(elem, appendElem, stylesToAdd) { // glue to DOM element // elem can be ID or actual DOM element object this.domElement = ZeroClipboard.$(elem); // float just above object, or zIndex 99 if dom element isn't set var zIndex = 99; if (this.domElement.style.zIndex) { zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; } if (typeof(appendElem) == 'string') { appendElem = ZeroClipboard.$(appendElem); } else if (typeof(appendElem) == 'undefined') { appendElem = document.getElementsByTagName('body')[0]; } // find X/Y position of domElement var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem); // create floating DIV above element this.div = document.createElement('div'); var style = this.div.style; style.position = 'absolute'; style.left = '' + box.left + 'px'; style.top = '' + box.top + 'px'; style.width = '' + box.width + 'px'; style.height = '' + box.height + 'px'; style.zIndex = zIndex; if (typeof(stylesToAdd) == 'object') { for (addedStyle in stylesToAdd) { style[addedStyle] = stylesToAdd[addedStyle]; } } // style.backgroundColor = '#f00'; // debug appendElem.appendChild(this.div); this.div.innerHTML = this.getHTML( box.width, box.height ); }, getHTML: function(width, height) { // return HTML for movie var html = ''; var flashvars = 'id=' + this.id + '&width=' + width + '&height=' + height; if (navigator.userAgent.match(/MSIE/)) { // IE gets an OBJECT tag var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; html += ''; } else { // all other browsers get an EMBED tag html += ''; } return html; }, hide: function() { // temporarily hide floater offscreen if (this.div) { this.div.style.left = '-2000px'; } }, show: function() { // show ourselves after a call to hide() this.reposition(); }, destroy: function() { // destroy control and floater if (this.domElement && this.div) { this.hide(); this.div.innerHTML = ''; var body = document.getElementsByTagName('body')[0]; try { body.removeChild( this.div ); } catch(e) {;} this.domElement = null; this.div = null; } }, reposition: function(elem) { // reposition our floating div, optionally to new container // warning: container CANNOT change size, only position if (elem) { this.domElement = ZeroClipboard.$(elem); if (!this.domElement) this.hide(); } if (this.domElement && this.div) { var box = ZeroClipboard.getDOMObjectPosition(this.domElement); var style = this.div.style; style.left = '' + box.left + 'px'; style.top = '' + box.top + 'px'; } }, setText: function(newText) { // set text to be copied to clipboard this.clipText = newText; if (this.ready) this.movie.setText(newText); }, addEventListener: function(eventName, func) { // add user event listener for event // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel eventName = eventName.toString().toLowerCase().replace(/^on/, ''); if (!this.handlers[eventName]) this.handlers[eventName] = []; this.handlers[eventName].push(func); }, setHandCursor: function(enabled) { // enable hand cursor (true), or default arrow cursor (false) this.handCursorEnabled = enabled; if (this.ready) this.movie.setHandCursor(enabled); }, setCSSEffects: function(enabled) { // enable or disable CSS effects on DOM container this.cssEffects = !!enabled; }, receiveEvent: function(eventName, args) { // receive event from flash eventName = eventName.toString().toLowerCase().replace(/^on/, ''); // special behavior for certain events switch (eventName) { case 'load': // movie claims it is ready, but in IE this isn't always the case... // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function this.movie = document.getElementById(this.movieId); if (!this.movie) { var self = this; setTimeout( function() { self.receiveEvent('load', null); }, 1 ); return; } // firefox on pc needs a "kick" in order to set these in certain cases if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { var self = this; setTimeout( function() { self.receiveEvent('load', null); }, 100 ); this.ready = true; return; } this.ready = true; this.movie.setText( this.clipText ); this.movie.setHandCursor( this.handCursorEnabled ); break; case 'mouseover': if (this.domElement && this.cssEffects) { this.domElement.addClass('hover'); if (this.recoverActive) this.domElement.addClass('active'); } break; case 'mouseout': if (this.domElement && this.cssEffects) { this.recoverActive = false; if (this.domElement.hasClass('active')) { this.domElement.removeClass('active'); this.recoverActive = true; } this.domElement.removeClass('hover'); } break; case 'mousedown': if (this.domElement && this.cssEffects) { this.domElement.addClass('active'); } break; case 'mouseup': if (this.domElement && this.cssEffects) { this.domElement.removeClass('active'); this.recoverActive = false; } break; } // switch eventName if (this.handlers[eventName]) { for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { var func = this.handlers[eventName][idx]; if (typeof(func) == 'function') { // actual function reference func(this, args); } else if ((typeof(func) == 'object') && (func.length == 2)) { // PHP style object + method, i.e. [myObject, 'myMethod'] func[0][ func[1] ](this, args); } else if (typeof(func) == 'string') { // name of function window[func](this, args); } } // foreach event handler defined } // user defined handler for event } };