Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Box-shadow generator

Our volunteers haven't translated this article into فارسی yet. Join us and help get the job done!

This tool lets you construct CSS box-shadow effects, to add box shadow effects to your CSS objects.

box-shadow generator

HTML Content

<div id="container">
    <div class="group section">
        <div id="layer_manager">
            <div class="group section">
                <div class="button" data-type="add"> </div>
                <div class="button" data-type="move-up"> </div>
                <div class="button" data-type="move-down"> </div>
            </div>
            <div id="stack_container"></div>
        </div>

        <div id="preview_zone">
            <div id="layer_menu" class="col span_12">
                <div class="button" id="element" data-type="subject" data-title="element"> element </div>
                <div class="button" id="before" data-type="subject" data-title=":before">
                    :before
                    <span class="delete" data-type="disable"></span>
                </div>
                <div class="button" id="after" data-type="subject" data-title=":after">
                    :after
                    <span class="delete" data-type="disable"></span>
                </div>
                <div class="ui-checkbox" data-topic='before' data-label=":before"></div>
                <div class="ui-checkbox" data-topic='after' data-label=":after"></div>
            </div>

            <div id="preview">
                <div id="obj-element">
                    <div class="content"> </div>
                    <div id="obj-before"> </div>
                    <div id="obj-after"> </div>
                </div>
            </div>
        </div>
    </div>

    <div id="controls" class="group section">
        <div class="wrap-left">
            <div class="colorpicker category">
                <div class="title"> </div>
                <div id="colorpicker" class="group">
                    <div id="gradient" class="gradient">
                        <div id="gradient_picker"> </div>
                    </div>
                    <div id="hue" data-topic="hue" class="hue">
                        <div id="hue_selector"> </div>
                    </div>
                    <div class="info">
                        <div class="input" data-topic="hue" data-title='H:' data-action="HSV"></div>
                        <div class="input" data-topic="saturation" data-title='S:' data-action="HSV"></div>
                        <div class="input" data-topic="value" data-title='V:' data-action="HSV"></div>
                    </div>
                    <div class="alpha">
                        <div id="alpha" data-topic="alpha">
                            <div id="alpha_selector"> </div>
                        </div>
                    </div>
                    <div class="info">
                        <div class="input" data-topic="r" data-title='R:' data-action="RGB"></div>
                        <div class="input" data-topic="g" data-title='G:' data-action="RGB"></div>
                        <div class="input" data-topic="b" data-title='B:' data-action="RGB"></div>
                    </div>
                    <div class="preview block">
                        <div id="output_color"> </div>
                    </div>
                    <div class="block info">
                        <div class="input" data-topic="a" data-title='alpha:' data-action="alpha"></div>
                        <div class="input" data-topic="hexa" data-title='' data-action="hexa"></div>
                    </div>
                </div>
            </div>
        </div>

        <div class="wrap-right">

            <div id="shadow_properties" class="category">
                <div class="title"> Shadow properties </div>
                <div class="group">
                    <div class="group property">
                        <div class="ui-slider-name"> inset </div>
                        <div class="ui-checkbox" data-topic='inset'></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Position x </div>
                        <div class="ui-slider-btn-set" data-topic="posX" data-type="sub"></div>
                        <div class="ui-slider" data-topic="posX"
                            data-min="-500" data-max="500" data-step="1"> </div>
                        <div class="ui-slider-btn-set" data-topic="posX" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="posX" data-unit="px"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Position y </div>
                        <div class="ui-slider-btn-set" data-topic="posY" data-type="sub"></div>
                        <div class="ui-slider" data-topic="posY"
                            data-min="-500" data-max="500" data-step="1"> </div>
                        <div class="ui-slider-btn-set" data-topic="posY" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="posY" data-unit="px"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Blur </div>
                        <div class="ui-slider-btn-set" data-topic="blur" data-type="sub"></div>
                        <div class="ui-slider" data-topic="blur"
                            data-min="0" data-max="200" data-step="1"> </div>
                        <div class="ui-slider-btn-set" data-topic="blur" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="blur" data-unit="px"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Spread </div>
                        <div class="ui-slider-btn-set" data-topic="spread" data-type="sub"></div>
                        <div class="ui-slider" data-topic="spread"
                            data-min="-100"    data-max="100" data-step="1" data-value="50">
                        </div>
                        <div class="ui-slider-btn-set" data-topic="spread" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="spread" data-unit="px"></div>
                    </div>
                </div>
            </div>

            <div id="element_properties" class="category">
                <div class="title"> Class element properties </div>
                <div class="group">
                    <div class="group property">
                        <div class="ui-slider-name"> border </div>
                        <div class="ui-checkbox" data-topic='border-state' data-state="true"></div>
                    </div>
                    <div id="z-index" class="slidergroup">
                        <div class="ui-slider-name"> z-index </div>
                        <div class="ui-slider-btn-set" data-topic="z-index" data-type="sub"></div>
                        <div class="ui-slider" data-topic="z-index"
                            data-min="-10" data-max="10" data-step="1"></div>
                        <div class="ui-slider-btn-set" data-topic="z-index" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="z-index"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> top </div>
                        <div class="ui-slider-btn-set" data-topic="top" data-type="sub"></div>
                        <div class="ui-slider" data-topic="top"
                            data-min="-500" data-max="500" data-step="1"> </div>
                        <div class="ui-slider-btn-set" data-topic="top" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="top" data-unit="px"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> left </div>
                        <div class="ui-slider-btn-set" data-topic="left" data-type="sub"></div>
                        <div class="ui-slider" data-topic="left"
                            data-min="-300" data-max="700" data-step="1"> </div>
                        <div class="ui-slider-btn-set" data-topic="left" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="left" data-unit="px"></div>
                    </div>
                    <div id="transform_rotate" class="slidergroup">
                        <div class="ui-slider-name"> Rotate </div>
                        <div class="ui-slider-btn-set" data-topic="rotate" data-type="sub"></div>
                        <div class="ui-slider" data-topic="rotate"
                            data-min="-360" data-max="360" data-step="1" data-value="0">
                        </div>
                        <div class="ui-slider-btn-set" data-topic="rotate" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="rotate" data-unit="deg"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Width </div>
                        <div class="ui-slider-btn-set" data-topic="width" data-type="sub"></div>
                        <div class="ui-slider" data-topic="width"
                            data-min="0" data-max="1000" data-step="1" data-value="200">
                        </div>
                        <div class="ui-slider-btn-set" data-topic="width" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="width"  data-unit="px"></div>
                    </div>
                    <div class="slidergroup">
                        <div class="ui-slider-name"> Height </div>
                        <div class="ui-slider-btn-set" data-topic="height" data-type="sub"></div>
                        <div class="ui-slider" data-topic="height"
                            data-min="0" data-max="400" data-step="1" data-value="200">
                        </div>
                        <div class="ui-slider-btn-set" data-topic="height" data-type="add"></div>
                        <div class="ui-slider-input" data-topic="height" data-unit="px"></div>
                    </div>
                </div>
            </div>

            <div id="output" class="category">
                <div id="menu" class="menu"></div>
                <div class="title">    CSS Code </div>
                <div class="group" style="border-top-left-radius: 0;">
                    <div class="output" data-topic="element" data-name="element"
                        data-prop="width height background-color position=[relative] box-shadow">
                    </div>
                    <div class="output" data-topic="before" data-name="element:before"
                        data-prop="content=[&quot;&quot;] position=[absolute] width height top left z-index background-color box-shadow transform -webkit-transform -ms-transform">
                    </div>
                    <div class="output" data-topic="after" data-name="element:after"
                        data-prop="content=[&quot;&quot;] position=[absolute] width height top left z-index background-color box-shadow transform -webkit-transform -ms-transform">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

CSS Content

/*  GRID OF TWELVE
 * ========================================================================== */

.span_12 {
	width: 100%;
}

.span_11 {
	width: 91.46%;
}

.span_10 {
	width: 83%;
}

.span_9 {
	width: 74.54%;
}

.span_8 {
	width: 66.08%;
}

.span_7 {
	width: 57.62%;
}

.span_6 {
	width: 49.16%;
}

.span_5 {
	width: 40.7%;
}

.span_4 {
	width: 32.24%;
}

.span_3 {
	width: 23.78%;
}

.span_2 {
	width: 15.32%;
}

.span_1 {
	width: 6.86%;
}


/*  SECTIONS
 * ========================================================================== */

.section {
	clear: both;
	padding: 0px;
	margin: 0px;
}

/*  GROUPING
 * ========================================================================== */


.group:before, .group:after {
    content: "";
    display: table;
}

.group:after {
    clear:both;
}

.group {
    zoom: 1; /* For IE 6/7 (trigger hasLayout) */
}

/*  GRID COLUMN SETUP
 * ========================================================================== */

.col {
	display: block;
	float:left;
	margin: 1% 0 1% 1.6%;
}

.col:first-child {
	margin-left: 0;
} /* all browsers except IE6 and lower */

/*
 * UI Slider
 */

.slidergroup {
	height: 20px;
	margin: 10px 0;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	-moz-user-select: none;
	user-select: none;
}

.slidergroup * {
	float: left;
	height: 100%;
	line-height: 100%;
}

/* Slider */

.ui-slider {
	height: 10px;
	width: 200px;
	margin: 4px 10px;
	display: block;
	border: 1px solid #999;
	border-radius: 3px;
	background: #EEE;
}

.ui-slider:hover {
	cursor: pointer;
}

.ui-slider-name {
	width: 90px;
	padding: 0 10px 0 0;
	text-align: right;
	text-transform: lowercase;
}

.ui-slider-pointer {
	width: 13px;
	height: 13px;
	background-color: #EEE;
	border: 1px solid #2C9FC9;
	border-radius: 3px;
	position: relative;
	top: -3px;
	left: 0%;
}

.ui-slider-btn-set {
	width: 25px;
	background-color: #2C9FC9;
	border-radius: 3px;
	color: #FFF;
	font-weight: bold;
	text-align: center;
}

.ui-slider-btn-set:hover {
	background-color: #379B4A;
	cursor: pointer;
}

.ui-slider-input > input {
	margin: 0 10px;
	padding: 0;
	width: 50px;
	text-align: center;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

/*
 * UI Button
 */

/* Checkbox */

.ui-checkbox {
	text-align: center;
	font-size: 16px;
	font-family: "Segoe UI", Arial, Helvetica, sans-serif;
	line-height: 1.5em;
	color: #FFF;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;
}

.ui-checkbox > input {
 	display: none;
}

.ui-checkbox > label {
	font-size: 12px;
	padding: 0.333em 1.666em 0.5em;
	height: 1em;
	line-height: 1em;

	background-color: #888;
	background-image: url("https://mdn.mozillademos.org/files/5683/disabled.png");
	background-position: center center;
	background-repeat: no-repeat;

	color: #FFF;
	border-radius: 3px;
	font-weight: bold;
	float: left;
}

.ui-checkbox .text {
	padding-left: 34px;
	background-position: center left 10px;
}

.ui-checkbox .left {
	padding-right: 34px;
	padding-left: 1.666em;
	background-position: center right 10px;
}

.ui-checkbox > label:hover {
	cursor: pointer;
}

.ui-checkbox > input:checked + label {
	background-image: url("https://mdn.mozillademos.org/files/5681/checked.png");
	background-color: #379B4A;
}

/*
 * BOX SHADOW GENERATOR TOOL
 */

body {
	max-width: 1000px;
	height: 800px;
	margin: 20px auto 0;

	font-family: "Segoe UI", Arial, Helvetica, sans-serif;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
}

#container {
	width: 100%;
	padding: 2px;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}


/* container with shadows stacks */
#stack_container {
	height: 400px;
	overflow: hidden;
	position: relative;
	border: 1px solid #CCC;
	border-radius: 3px;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#stack_container .container {
	height: 100%;
	width: 100%;
	position: absolute;
	left: 100%;
	transition-property: left;
	transition-duration: 0.5s;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}


#stack_container .title {
	text-align: center;
	font-weight: bold;
	line-height: 2em;
	border-bottom: 1px solid #43A6E1;
	color: #666;
}


/*
 * Stack of Layers for shadow
 */

#layer_manager {
	width: 17%;
	background-color: #FEFEFE;
	margin: 0 1% 0 0;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	float: left;
}


#layer_manager .button {
	width: 30%;
	height: 25px;
	margin:0 0 10px;
	color: #333;
	background-color: #EEE;
	text-align: center;
	font-size: 0.75em;
	line-height: 1.5em;
	border: 1px solid #CCC;
	border-radius: 3px;

	display: block;
	background-position: center center;
	background-repeat: no-repeat;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	float: left;
}

#layer_manager .button:hover {
	background-color: #3380C4;
	border: 1px solid #3380C4;
	cursor: pointer;
}

#layer_manager [data-type='add'] {
	background-image: url("https://mdn.mozillademos.org/files/5685/add-black.png");
}

#layer_manager [data-type='add']:hover {
	background-image: url("https://mdn.mozillademos.org/files/5687/add-white.png");
}

#layer_manager [data-type='move-up'] {
	background-image: url("https://mdn.mozillademos.org/files/5697/up-black.png");
	margin-left: 5%;
	margin-right: 5%;
}

#layer_manager [data-type='move-up']:hover {
	background-image: url("https://mdn.mozillademos.org/files/5709/up-white.png");
}

#layer_manager [data-type='move-down'] {
	background-image: url("https://mdn.mozillademos.org/files/5693/down-black.png");
}

#layer_manager [data-type='move-down']:hover {
	background-image: url("https://mdn.mozillademos.org/files/5695/down-white.png");
}

/* shadows classes */

#layer_manager .node {
	width: 100%;
	margin: 5px 0;
	padding: 5px;
	text-align: center;
	background-color: #EEE;
	border: 1px solid #DDD;
	font-size: 0.75em;
	line-height: 1.5em;
	color: #333;
	border-radius: 3px;

	position: relative;
	display: block;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#layer_manager .node:hover {
	color: #FFF;
	background-color: #3380C4;
	cursor: pointer;
}

/* active element styling */

#layer_manager [data-active='layer'] {
	color: #FFF;
	border: none;
	background-color: #379B4A;
}

#layer_manager [data-active='subject'] {
	color: #FFF;
	background-color: #467FC9;
}

/* delete button */

#layer_manager .delete {
	width: 1.5em;
	height: 100%;
	float: right;
	border-radius: 3px;
	background-image: url("https://mdn.mozillademos.org/files/5689/delete-white.png");
	background-position: center center;
	background-repeat: no-repeat;
	position: absolute;
	top: 0;
	right: 10px;
	display: none;
}

#layer_manager .delete:hover {
	background-image: url("https://mdn.mozillademos.org/files/5691/delete-yellow.png");
}

#layer_manager .node:hover .delete {
	display: block;
}


#layer_manager .stack {
	padding: 0 5px;
	max-height: 90%;
	overflow: auto;
	overflow-x: hidden;
}


/*
 * Layer Menu
 */

#layer_menu {
	margin: 0 0 10px 0;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#layer_menu .button {
	width: 100px;
	margin: 0 5px 0 0;
	padding: 2.5px;
	color: #333;
	background-color: #EEE;
	border: 1px solid #CCC;
	border-radius: 3px;
	text-align: center;
	font-size: 0.75em;
	line-height: 1.5em;

	position: relative;
	display: block;
	float: left;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#layer_menu .button:hover {
	color: #FFF;
	background-color: #3380C4;
	border: 1px solid #3380C4;
	cursor: pointer;
}

#layer_menu .delete {
	width: 1.5em;
	height: 100%;
	float: right;
	border-radius: 3px;
	background-image: url("https://mdn.mozillademos.org/files/5689/delete-white.png");
	background-position: center center;
	background-repeat: no-repeat;
	position: absolute;
	top: 0;
	right: 5px;
	display: none;
}

#layer_menu .delete:hover {
	background-image: url("https://mdn.mozillademos.org/files/5691/delete-yellow.png");
}

#layer_menu .button:hover .delete {
	display: block;
}


/*
 * active element styling
 */

#layer_menu [data-active='subject'] {
	color: #FFF;
	background-color: #379B4A;
	border: 1px solid #379B4A;
}


/* Checkbox */

#layer_menu .ui-checkbox > label {
	height: 15px;
	line-height: 17px;
	font-weight: normal;
	width: 46px;
	margin: 0 5px 0 0;
}

#layer_menu .ui-checkbox > input:checked + label {
	display: none;
}


/******************************************************************************/
/******************************************************************************/
/*
 * Preview Area
 */

#preview_zone {
	width: 82%;
	float: left;

}


#preview {
	width: 100%;
	height: 400px;
	border: 1px solid #CCC;
	border-radius: 3px;
	text-align: center;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	cursor: move;
	float: left;
}

#preview .content {
	width: 100%;
	height: 100%;
	display: block;
}

#obj-element {
	width: 300px;
	height: 100px;
	border: 1px solid #CCC;
	background: #FFF;
	position: relative;
}


#obj-before {
	height: 100%;
	width: 100%;
	background: #999;
	border: 1px solid #CCC;
	text-align: left;
	display : block;
	position: absolute;
	z-index: -1;
}

#obj-after {
	height: 100%;
	width: 100%;
	background: #DDD;
	border: 1px solid #CCC;
	text-align: right;
	display : block;
	position: absolute;
	z-index: -1;
}


/******************************************************************************/
/******************************************************************************/

/**
 * Controls
 */

.wrap-left {
	float: left;
	overflow: hidden;
}

.wrap-right {
	float: right;
	overflow: hidden;
}

.wrap-left > * {
	float: left;
}

.wrap-right > * {
	float: right;
}

@media (min-width: 960px) {

	.wrap-left {
		width: 45%;
	}

	.wrap-right {
		width: 55%;
	}
}


@media (max-width: 959px) {

	.wrap-left {
		width: 30%;
	}

	.wrap-right {
		width: 70%;
	}
}


#controls {
	color: #444;
	margin: 10px 0 0 0;
}


#controls .category {
	width: 500px;
	margin: 0 auto 20px;
	padding: 0;

}

#controls .category .title {
	width: 100%;
	height: 1.5em;
	line-height: 1.5em;
	color: #AAA;
	text-align: right;
}

#controls .category > .group {
	border: 1px solid #CCC;
	border-radius: 3px;
}


/**
 * 	Color Picker
 */

@media (min-width: 960px) {
	#controls .colorpicker {
		width: 420px;
	}
}

@media (max-width: 959px) {
	#controls .colorpicker {
		width: 210px;
	}
}

#colorpicker {
	width: 100%;
	margin: 0 auto;
}

#colorpicker .gradient {
	width: 200px;
	height: 200px;
	margin: 5px;
	background: url("https://mdn.mozillademos.org/files/5707/picker_mask_200.png");
	background: -moz-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-moz-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background: -webkit-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%),
				-webkit-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%);
	background-color: #F00;
	float: left;
}

#colorpicker .hue {
	width: 200px;
	height: 30px;
	margin: 5px;
	background: url("https://mdn.mozillademos.org/files/5701/hue.png");
	background: -moz-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	background: -webkit-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%,
				#00F 66.66%, #F0F 83.33%, #F00 100%);
	float: left;
}

#colorpicker .alpha {
	width: 200px;
	height: 30px;
	margin: 5px;
	border: 1px solid #CCC;
	float: left;
	background: url("https://mdn.mozillademos.org/files/5705/alpha.png");

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#colorpicker #alpha {
	width: 100%;
	height: 100%;
	background: url("https://mdn.mozillademos.org/files/5703/alpha_mask.png");
	background: -moz-linear-gradient(left, rgba(255, 0, 0, 0) 0%, rgba(255, 0, 0, 1) 100%);
}

#colorpicker #gradient_picker {
	width: 0.5em;
	height: 0.5em;
	border-radius: 0.4em;
	border: 2px solid #CCC;
	position: relative;
	top: 20%;
	left: 20%;
}

#colorpicker #hue_selector,
#colorpicker #alpha_selector {
	width: 3px;
	height: 100%;
	border: 1px solid #777;
	background-color: #FFF;
	position: relative;
	top: -1px;
	left: 0%;
}

/* input HSV and RGB */
#colorpicker .info {
	width: 200px;
	margin: 5px;
	float: left;
}

#colorpicker .info * {
	float: left;
}

#colorpicker .info input {
	margin: 0;
	text-align: center;
	width: 30px;
	-moz-user-select: text;
	-webkit-user-select: text;
	-ms-user-select: text;
}

#colorpicker .info span {
	height: 20px;
	width: 30px;
	text-align: center;
	line-height: 20px;
	display: block;
}

/* Preview color */
#colorpicker .block {
	width: 95px;
	height: 54px;
	float: left;
	position: relative;
}

#colorpicker .preview {
	margin: 5px;
	border: 1px solid #CCC;
	background-image: url("https://mdn.mozillademos.org/files/5705/alpha.png");

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

#colorpicker .preview:before {
	height: 100%;
	width: 50%;
	left: 50%;
	content: "";
	background: #FFF;
	position: absolute;
	z-index: 1;
}

#colorpicker .preview > * {
	width: 50%;
	height: 100%;
}

#colorpicker #output_color {
	width: 100%;
	height: 100%;
	position: absolute;
	z-index: 2;
}

#colorpicker .block .input {
	float: right;
}

#colorpicker [data-topic="a"] > span {
	width: 50px;
}

#colorpicker [data-topic="hexa"] {
	float: right;
	margin: 10px 0 0 0;
}

#colorpicker [data-topic="hexa"] > span {
	display: none;
}

#colorpicker [data-topic="hexa"] > input {
	width: 85px;
	padding: 2px 0;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}


/*
 * UI Components
 */

/* Property */

.property {
	height: 20px;
	margin: 10px 0;
}

.property * {
	float: left;
	height: 100%;
	line-height: 100%;
}

/* Slider */

#controls .ui-slider-name {
	margin: 0 10px 0 0;
}

/*
 * Output code styling
 */

#output {
	position: relative;
}

#output .menu {
	max-width: 70%;
	height: 20px;
	position: absolute;
	top: 2px;
}

#output .button {
	width: 90px;
	height: 22px;
	margin: 0 5px 0 0;
	text-align: center;
	line-height: 20px;
	font-size: 14px;
	color: #FFF;
	background-color: #999;
	border-top-left-radius: 3px;
	border-top-right-radius: 3px;
	bottom: -5px;
	float:left;
}

#output .button:hover {
	color: #FFF;
	background-color: #666;
	cursor: pointer;
}

#output .menu [data-active="true"] {
	color: #777;
	background-color: #FFF;
	border: 1px solid #CCC;
	border-bottom: none;
}

#output .menu [data-topic="before"] {
	left: 100px;
}

#output .menu [data-topic="after"] {
	left: 200px;
}

#output .output {
	width: 480px;
	margin: 10px;
	padding: 10px;
	overflow: hidden;
	color: #555;
	font-size: 14px;
	border: 1px dashed #CCC;
	border-radius: 3px;
	display: none;

	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;

	-moz-user-select: text;
	-webkit-user-select: text;
	-ms-user-select: text;
}

#output .css-property {
	width: 100%;
	float: left;
	white-space: pre;
}

#output .name {
	width: 35%;
	float: left;
}

#output .value {
	width: 65%;
	float: left;
}

JavaScript Content



'use strict';

/**
 * UI-SlidersManager
 */

var SliderManager = (function SliderManager() {

	var subscribers = {};
	var sliders = [];

	var Slider = function(node) {
		var min = node.getAttribute('data-min') | 0;
		var max = node.getAttribute('data-max') | 0;
		var step = node.getAttribute('data-step') | 0;
		var value = node.getAttribute('data-value') | 0;
		var snap = node.getAttribute('data-snap');
		var topic = node.getAttribute('data-topic');

		this.min = min;
		this.max = max > 0 ? max : 100;
		this.step = step === 0 ? 1 : step;
		this.value = value <= max && value >= min ? value : (min + max) / 2 | 0;
		this.snap = snap === "true" ? true : false;
		this.topic = topic;
		this.node = node;

		var pointer = document.createElement('div');
		pointer.className = 'ui-slider-pointer';
		node.appendChild(pointer);
		this.pointer = pointer;

		setMouseTracking(node, updateSlider.bind(this));

		sliders[topic] = this;
		setValue(topic, this.value);
	}

	var setButtonComponent = function setButtonComponent(node) {
		var type = node.getAttribute('data-type');
		var topic = node.getAttribute('data-topic');
		if (type === "sub") {
			node.textContent = '-';
			node.addEventListener("click", function() {
				decrement(topic);
			});
		}
		if (type === "add") {
			node.textContent = '+';
			node.addEventListener("click", function() {
				increment(topic);
			});
		}
	}

	var setInputComponent = function setInputComponent(node) {
		var topic		= node.getAttribute('data-topic');
		var unit_type	= node.getAttribute('data-unit');

		var input = document.createElement('input');
		var unit = document.createElement('span');
		unit.textContent = unit_type;

		input.setAttribute('type', 'text');
		node.appendChild(input);
		node.appendChild(unit);

		input.addEventListener('click', function(e) {
			this.select();
		});

		input.addEventListener('change', function(e) {
			setValue(topic, e.target.value | 0);
		});

		subscribe(topic, function(value) {
			node.children[0].value = value;
		});
	}

	var increment = function increment(topic) {
		var slider = sliders[topic];
		if (slider === null || slider === undefined)
			return;

		if (slider.value + slider.step <= slider.max) {
			slider.value += slider.step;
			setValue(slider.topic, slider.value)
			notify.call(slider);
		}
	};

	var decrement = function decrement(topic) {
		var slider = sliders[topic];
		if (slider === null || slider === undefined)
			return;

		if (slider.value - slider.step >= slider.min) {
			slider.value -= slider.step;
			setValue(topic, slider.value)
			notify.call(slider);
		}
	}

	// this = Slider object
	var updateSlider = function updateSlider(e) {
		var node = this.node;
		var pos = e.pageX - node.offsetLeft;
		var width = node.clientWidth;
		var delta = this.max - this.min;
		var offset = this.pointer.clientWidth + 4; // border width * 2

		if (pos < 0) pos = 0;
		if (pos > width) pos = width;

		var value = pos * delta / width | 0;
		var precision = value % this.step;
		value = value - precision + this.min;
		if (precision > this.step / 2)
			value = value + this.step;

		if (this.snap)
			pos =  (value - this.min) * width / delta;

		this.pointer.style.left = pos - offset/2 + "px";
		this.value = value;
		node.setAttribute('data-value', value);
		notify.call(this);
	}

	var setValue = function setValue(topic, value) {
		var slider = sliders[topic];

		if (value > slider.max || value < slider.min)
			return;

		var delta = slider.max - slider.min;
		var width = slider.node.clientWidth;
		var offset = slider.pointer.clientWidth;
		var pos =  (value - slider.min) * width / delta;
		slider.value = value;
		slider.pointer.style.left = pos - offset / 2 + "px";
		slider.node.setAttribute('data-value', value);
		notify.call(slider);
	}

	var setMouseTracking = function setMouseTracking(elem, callback) {
		elem.addEventListener("mousedown", function(e) {
			callback(e);
			document.addEventListener("mousemove", callback);
		});

		document.addEventListener("mouseup", function(e) {
			document.removeEventListener("mousemove", callback);
		});
	}

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];
		subscribers[topic].push(callback);
	}

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	}

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;

		for (var i in subscribers[this.topic]) {
			subscribers[this.topic][i](this.value);
		}
	}

	var init = function init() {
		var elem, size;

		elem = document.querySelectorAll('.ui-slider-btn-set');
		size = elem.length;
		for (var i = 0; i < size; i++)
			setButtonComponent(elem[i]);

		elem = document.querySelectorAll('.ui-slider-input');
		size = elem.length;
		for (var i = 0; i < size; i++)
			setInputComponent(elem[i]);

		elem = document.querySelectorAll('.ui-slider');
		size = elem.length;
		for (var i = 0; i < size; i++)
			new Slider(elem[i]);
	}

	return {
		init : init,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe
	}

})();

/**
 * UI-ButtonManager
 */

var ButtonManager = (function CheckBoxManager() {

	var subscribers = [];
	var buttons = [];

	var CheckBox = function CheckBox(node) {
		var topic = node.getAttribute('data-topic');
		var state = node.getAttribute('data-state');
		var name = node.getAttribute('data-label');
		var align = node.getAttribute('data-text-on');

		state = (state === "true");

		var checkbox = document.createElement("input");
		var label = document.createElement("label");

		var id = 'checkbox-' + topic;
		checkbox.id = id;
		checkbox.setAttribute('type', 'checkbox');
		checkbox.checked = state;

		label.setAttribute('for', id);
		if (name) {
			label.className = 'text';
			if (align)
				label.className += ' ' + align;
			label.textContent = name;
		}

		node.appendChild(checkbox);
		node.appendChild(label);

		this.node = node;
		this.topic = topic;
		this.checkbox = checkbox;

		checkbox.addEventListener('change', function(e) {
			notify.call(this);
		}.bind(this));

		buttons[topic] = this;
	}

	var getNode =  function getNode(topic) {
		return buttons[topic].node;
	}

	var setValue = function setValue(topic, value) {
		try {
			buttons[topic].checkbox.checked = value;
			notify.call(buttons[topic]);
		}
		catch(error) {
			console.log(error, topic, value);
		}
	}

	var subscribe = function subscribe(topic, callback) {
		if (subscribers[topic] === undefined)
			subscribers[topic] = [];

		subscribers[topic].push(callback);
	}

	var unsubscribe = function unsubscribe(topic, callback) {
		subscribers[topic].indexOf(callback);
		subscribers[topic].splice(index, 1);
	}

	var notify = function notify() {
		if (subscribers[this.topic] === undefined)
			return;
		for (var i = 0; i < subscribers[this.topic].length; i++)
			subscribers[this.topic][i](this.checkbox.checked);
	}

	var init = function init() {
		var elem = document.querySelectorAll('.ui-checkbox');
		var size = elem.length;
		for (var i = 0; i < size; i++)
			new CheckBox(elem[i]);
	}

	return {
		init : init,
		setValue : setValue,
		subscribe : subscribe,
		unsubscribe : unsubscribe
	}

})();


window.addEventListener("load", function(){
	BoxShadow.init();
});

var BoxShadow = (function BoxShadow() {

	function getElemById(id) {
		return document.getElementById(id);
	}

	/**
	 * RGBA Color class
	 */

	function Color() {
		this.r = 0;
		this.g = 0;
		this.b = 0;
		this.a = 1;
		this.hue = 0;
		this.saturation = 0;
		this.value = 0;
	}

	Color.prototype.copy = function copy(obj) {
		if(obj instanceof Color !== true) {
			console.log("Typeof instance not Color");
			return;
		}

		this.r = obj.r;
		this.g = obj.g;
		this.b = obj.b;
		this.a = obj.a;
		this.hue = obj.hue;
		this.saturation = obj.saturation;
		this.value = obj.value;
	}

	Color.prototype.setRGBA = function setRGBA(red, green, blue, alpha) {
		if (red != undefined)
			this.r = red | 0;
		if (green != undefined)
			this.g = green | 0;
		if (blue != undefined)
			this.b = blue | 0;
		if (alpha != undefined)
			this.a = alpha | 0;
	}

	/**
	 * HSV/HSB (hue, saturation, value / brightness)
	 * @param hue			0-360
	 * @param saturation	0-100
	 * @param value 		0-100
	 */
	Color.prototype.setHSV = function setHSV(hue, saturation, value) {
		this.hue = hue;
		this.saturation = saturation;
		this.value = value;
		this.updateRGB();
	}

	Color.prototype.updateRGB = function updateRGB() {
		var sat = this.saturation / 100;
		var value = this.value / 100;
		var C = sat * value;
		var H = this.hue / 60;
		var X = C * (1 - Math.abs(H % 2 - 1));
		var m = value - C;
		var precision = 255;

		C = (C + m) * precision;
		X = (X + m) * precision;
		m = m * precision;

		if (H >= 0 && H < 1) {	this.setRGBA(C, X, m);	return; }
		if (H >= 1 && H < 2) {	this.setRGBA(X, C, m);	return; }
		if (H >= 2 && H < 3) {	this.setRGBA(m, C, X);	return; }
		if (H >= 3 && H < 4) {	this.setRGBA(m, X, C);	return; }
		if (H >= 4 && H < 5) {	this.setRGBA(X, m, C);	return; }
		if (H >= 5 && H < 6) {	this.setRGBA(C, m, X);	return; }
	}

	Color.prototype.updateHSV = function updateHSV() {
		var red		= this.r / 255;
		var green	= this.g / 255;
		var blue	= this.b / 255;

		var cmax = Math.max(red, green, blue);
		var cmin = Math.min(red, green, blue);
		var delta = cmax - cmin;
		var hue = 0;
		var saturation = 0;

		if (delta) {
			if (cmax === red ) { hue = ((green - blue) / delta); }
			if (cmax === green ) { hue = 2 + (blue - red) / delta; }
			if (cmax === blue ) { hue = 4 + (red - green) / delta; }
			if (cmax) saturation = delta / cmax;
		}

		this.hue = 60 * hue | 0;
		if (this.hue < 0) this.hue += 360;
		this.saturation = (saturation * 100) | 0;
		this.value = (cmax * 100) | 0;
	}

	Color.prototype.setHexa = function setHexa(value) {
		var valid  = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)/i.test(value)
		if (valid !== true)
			return;

		if (value[0] === '#')
			value = value.slice(1, value.length);

		if (value.length === 3)
			value = value.replace(/([0-9A-F])([0-9A-F])([0-9A-F])/i,"$1$1$2$2$3$3");

		this.r = parseInt(value.substr(0, 2), 16);
		this.g = parseInt(value.substr(2, 2), 16);
		this.b = parseInt(value.substr(4, 2), 16);

		this.alpha	= 1;
	}

	Color.prototype.getHexa = function getHexa() {
		var r = this.r.toString(16);
		var g = this.g.toString(16);
		var b = this.b.toString(16);
		if (this.r < 16) r = '0' + r;
		if (this.g < 16) g = '0' + g;
		if (this.b < 16) b = '0' + b;
		var value = '#' + r + g + b;
		return value.toUpperCase();
	}

	Color.prototype.getRGBA = function getRGBA() {

		var rgb = "(" + this.r + ", " + this.g + ", " + this.b;
		var a = '';
		var v = '';
		if (this.a !== 1) {
			a = 'a';
			v = ', ' + this.a;
		}

		var value = "rgb" + a + rgb + v + ")";
		return value;
	}

	Color.prototype.getColor = function getColor() {
		if (this.a | 0 === 1)
			return this.getHexa();
		return this.getRGBA();
	}

	/**
	 * Shadow Object
	 */
	function Shadow() {
		this.inset  = false;
		this.posX   = 5;
		this.posY   = -5;
		this.blur   = 5;
		this.spread = 0;
		this.color  = new Color();

		var hue			= (Math.random() * 360) | 0;
		var saturation	= (Math.random() * 75) | 0;
		var value 		= (Math.random() * 50 + 50) | 0;
		this.color.setHSV(hue, saturation, value, 1);
	}

	Shadow.prototype.computeCSS = function computeCSS() {
		var value = "";
		if (this.inset === true)
			value += "inset ";
		value += this.posX + "px ";
		value += this.posY + "px ";
		value += this.blur + "px ";
		value += this.spread + "px ";
		value += this.color.getColor();

		return value;
	}

	Shadow.prototype.toggleInset = function toggleInset(value) {
		if (value !== undefined || typeof value === "boolean")
			this.inset = value;
		else
			this.inset = this.inset === true ? false : true;
	}

	Shadow.prototype.copy = function copy(obj) {
		if(obj instanceof Shadow !== true) {
			console.log("Typeof instance not Shadow");
			return;
		}

		this.inset  = obj.inset;
		this.posX   = obj.posX;
		this.posY   = obj.posY;
		this.blur   = obj.blur;
		this.spread = obj.spread;
		this.color.copy(obj.color);
	}

	/**
	 * Color Picker
	 */
	var ColoPicker = (function ColoPicker() {

		var colorpicker;
		var hue_area;
		var gradient_area;
		var alpha_area;
		var gradient_picker;
		var hue_selector;
		var alpha_selector;
		var pick_object;
		var info_rgb;
		var info_hsv;
		var info_hexa;
		var output_color;
		var color = new Color();
		var subscribers = [];

		var updateColor = function updateColor(e) {
			var x = e.pageX - gradient_area.offsetLeft;
			var y = e.pageY - gradient_area.offsetTop;

			// width and height should be the same
			var size = gradient_area.clientWidth;

			if (x > size)
				x = size;
			if (y > size)
				y = size;

			if (x < 0) x = 0;
			if (y < 0) y = 0;

			var value = 100 - (y * 100 / size) | 0;
			var saturation = x * 100 / size | 0;

			color.setHSV(color.hue, saturation, value);
			// should update just
			// color pointer location
			updateUI();
			notify("color", color);
		}

		var updateHue = function updateHue(e) {
			var x = e.pageX - hue_area.offsetLeft;
			var width = hue_area.clientWidth;

			if (x < 0) x = 0;
			if (x > width) x = width;

			var hue = ((360 * x) / width) | 0;
			if (hue === 360) hue = 359;

			color.setHSV(hue, color.saturation, color.value);

			// should update just
			// hue pointer location
			// picker area background
			// alpha area background
			updateUI();
			notify("color", color);
		}

		var updateAlpha = function updateAlpha(e) {
			var x = e.pageX - alpha_area.offsetLeft;
			var width = alpha_area.clientWidth;

			if (x < 0) x = 0;
			if (x > width) x = width;

			color.a = (x / width).toFixed(2);

			// should update just
			// alpha pointer location
			updateUI();
			notify("color", color);
		}

		var setHueGfx = function setHueGfx(hue) {
			var sat = color.saturation;
			var val = color.value;
			var alpha = color.a;

			color.setHSV(hue, 100, 100);
			gradient_area.style.backgroundColor = color.getHexa();

			color.a = 0;
			var start = color.getRGBA();
			color.a = 1;
			var end = color.getRGBA();
			color.a = alpha;

			var gradient = '-moz-linear-gradient(left, ' +	start + '0%, ' + end + ' 100%)';
			alpha_area.style.background = gradient;
		}

		var updateUI = function updateUI() {
			var x, y;		// coordinates
			var size;		// size of the area
			var offset;		// pointer graphic selector offset

			// Set color pointer location
			size = gradient_area.clientWidth;
			offset = gradient_picker.clientWidth / 2 + 2;

			x = (color.saturation * size / 100) | 0;
			y = size - (color.value * size / 100) | 0;

			gradient_picker.style.left = x - offset + "px";
			gradient_picker.style.top = y - offset + "px";

			// Set hue pointer location
			size = hue_area.clientWidth;
			offset = hue_selector.clientWidth/2;
			x = (color.hue * size / 360 ) | 0;
			hue_selector.style.left = x - offset + "px";

			// Set alpha pointer location
			size = alpha_area.clientWidth;
			offset = alpha_selector.clientWidth/2;
			x = (color.a * size) | 0;
			alpha_selector.style.left = x - offset + "px";

			// Set picker area background
			var nc = new Color();
			nc.copy(color);
			if (nc.hue === 360) nc.hue = 0;
			nc.setHSV(nc.hue, 100, 100);
			gradient_area.style.backgroundColor = nc.getHexa();

			// Set alpha area background
			nc.copy(color);
			nc.a = 0;
			var start = nc.getRGBA();
			nc.a = 1;
			var end = nc.getRGBA();
			var gradient = '-moz-linear-gradient(left, ' +	start + '0%, ' + end + ' 100%)';
			alpha_area.style.background = gradient;

			// Update color info
			notify("color", color);
			notify("hue", color.hue);
			notify("saturation", color.saturation);
			notify("value", color.value);
			notify("r", color.r);
			notify("g", color.g);
			notify("b", color.b);
			notify("a", color.a);
			notify("hexa", color.getHexa());
			output_color.style.backgroundColor = color.getRGBA();
		}

		var setInputComponent = function setInputComponent(node) {
			var topic = node.getAttribute('data-topic');
			var title = node.getAttribute('data-title');
			var action = node.getAttribute('data-action');
			title = title === null ? '' : title;

			var input = document.createElement('input');
			var info = document.createElement('span');
			info.textContent = title;

			input.setAttribute('type', 'text');
			input.setAttribute('data-action', 'set-' + action + '-' + topic);
			node.appendChild(info);
			node.appendChild(input);

			input.addEventListener('click', function(e) {
				this.select();
			});

			input.addEventListener('change', function(e) {
				if (action === 'HSV')
					inputChangeHSV(topic);
				if (action === 'RGB')
					inputChangeRGB(topic);
				if (action === 'alpha')
					inputChangeAlpha(topic);
				if (action === 'hexa')
					inputChangeHexa(topic);
			});

			subscribe(topic, function(value) {
				node.children[1].value = value;
			});
		}

		var inputChangeHSV = function actionHSV(topic) {
			var selector = "[data-action='set-HSV-" + topic + "']";
			var node = document.querySelector("#colorpicker " + selector);
			var value = parseInt(node.value);

			if (typeof value === 'number' && isNaN(value) === false &&
				value >= 0 && value < 360)
				color[topic] = value;

			color.updateRGB();
			updateUI();
		}

		var inputChangeRGB = function inputChangeRGB(topic) {
			var selector = "[data-action='set-RGB-" + topic + "']";
			var node = document.querySelector("#colorpicker " + selector);
			var value = parseInt(node.value);

			if (typeof value === 'number' && isNaN(value) === false &&
				value >= 0 && value <= 255)
				color[topic] = value;

			color.updateHSV();
			updateUI();
		}

		var inputChangeAlpha = function inputChangeAlpha(topic) {
			var selector = "[data-action='set-alpha-" + topic + "']";
			var node = document.querySelector("#colorpicker " + selector);
			var value = parseFloat(node.value);

			if (typeof value === 'number' && isNaN(value) === false &&
				value >= 0 && value <= 1)
				color.a = value.toFixed(2);

			updateUI();
		}

		var inputChangeHexa = function inputChangeHexa(topic) {
			var selector = "[data-action='set-hexa-" + topic + "']";
			var node = document.querySelector("#colorpicker " + selector);
			var value = node.value;
			color.setHexa(value);
			color.updateHSV();
			updateUI();
		}

		var setMouseTracking = function setMouseTracking(elem, callback) {

			elem.addEventListener("mousedown", function(e) {
				callback(e);
				document.addEventListener("mousemove", callback);
			});

			document.addEventListener("mouseup", function(e) {
				document.removeEventListener("mousemove", callback);
			});
		}

		/*
		 * Observer
		 */
		var setColor = function setColor(obj) {
			if(obj instanceof Color !== true) {
				console.log("Typeof instance not Color");
				return;
			}
			color.copy(obj);
			updateUI();
		}

		var subscribe = function subscribe(topic, callback) {
			if (subscribers[topic] === undefined)
				subscribers[topic] = [];

			subscribers[topic].push(callback);
		}

		var unsubscribe = function unsubscribe(callback) {
			subscribers.indexOf(callback);
			subscribers.splice(index, 1);
		}

		var notify = function notify(topic, value) {
			for (var i in subscribers[topic])
				subscribers[topic][i](value);
		}

		var init = function init() {
			colorpicker		= getElemById("colorpicker");
			hue_area		= getElemById("hue");
			gradient_area	= getElemById("gradient");
			alpha_area		= getElemById("alpha");
			gradient_picker	= getElemById("gradient_picker");
			hue_selector	= getElemById("hue_selector");
			alpha_selector	= getElemById("alpha_selector");
			output_color	= getElemById("output_color");

			var elem = document.querySelectorAll('#colorpicker .input');
			var size = elem.length;
			for (var i = 0; i < size; i++)
				setInputComponent(elem[i]);

			setMouseTracking(gradient_area, updateColor);
			setMouseTracking(hue_area, updateHue);
			setMouseTracking(alpha_area, updateAlpha);

		}

		return {
			init : init,
			setColor : setColor,
			subscribe : subscribe,
			unsubscribe : unsubscribe
		}

	})();

	/**
	 * Shadow dragging
	 */
	var PreviewMouseTracking = (function Drag() {
		var active = false;
		var lastX = 0;
		var lastY = 0;
		var subscribers = [];

		var init = function init(id) {
			var elem = getElemById(id);
			elem.addEventListener('mousedown', dragStart, false);
			document.addEventListener('mouseup', dragEnd, false);
		}

		var dragStart = function dragStart(e) {
			if (e.button !== 0)
				return;

			active = true;
			lastX = e.clientX;
			lastY = e.clientY;
			document.addEventListener('mousemove', mouseDrag, false);
		}

		var dragEnd = function dragEnd(e) {
			if (e.button !== 0)
				return;

			if (active === true) {
				active = false;
				document.removeEventListener('mousemove', mouseDrag, false);
			}
		}

		var mouseDrag = function mouseDrag(e) {
			notify(e.clientX - lastX, e.clientY - lastY);
			lastX = e.clientX;
			lastY = e.clientY;
		}

		var subscribe = function subscribe(callback) {
			subscribers.push(callback);
		}

		var unsubscribe = function unsubscribe(callback) {
			var index = subscribers.indexOf(callback);
			subscribers.splice(index, 1);
		}

		var notify = function notify(deltaX, deltaY) {
			for (var i in subscribers)
				subscribers[i](deltaX, deltaY);
		}

		return {
			init : init,
			subscribe : subscribe,
			unsubscribe : unsubscribe
		}

	})();

	/*
	 * Element Class
	 */
	var CssClass = function CssClass(id) {
		this.left = 0;
		this.top = 0;
		this.rotate = 0;
		this.width = 300;
		this.height = 100;
		this.display = true;
		this.border = true;
		this.zIndex = -1;
		this.bgcolor = new Color();
		this.id = id;
		this.node = getElemById('obj-' + id);
		this.object = getElemById(id);
		this.shadowID = null;
		this.shadows = []
		this.render = [];
		this.init();
	}

	CssClass.prototype.init = function init() {
		this.left = ((this.node.parentNode.clientWidth - this.node.clientWidth) / 2) | 0;
		this.top = ((this.node.parentNode.clientHeight - this.node.clientHeight) / 2) | 0;

		this.setTop(this.top);
		this.setLeft(this.left);
		this.setHeight(this.height);
		this.setWidth(this.width);
		this.bgcolor.setHSV(0, 0, 100);
		this.updateBgColor(this.bgcolor);
	}

	CssClass.prototype.updatePos = function updatePos(deltaX, deltaY) {
		this.left += deltaX;
		this.top += deltaY;
		this.node.style.top = this.top + "px";
		this.node.style.left = this.left + "px";
		SliderManager.setValue("left", this.left);
		SliderManager.setValue("top", this.top);
	}

	CssClass.prototype.setLeft = function setLeft(value) {
		this.left = value;
		this.node.style.left = this.left + "px";
		OutputManager.updateProperty(this.id, 'left', this.left + 'px');
	}

	CssClass.prototype.setTop = function setTop(value) {
		this.top = value;
		this.node.style.top = this.top + 'px';
		OutputManager.updateProperty(this.id, 'top', this.top + 'px');
	}

	CssClass.prototype.setWidth = function setWidth(value) {
		this.width = value;
		this.node.style.width = this.width + 'px';
		OutputManager.updateProperty(this.id, 'width', this.width + 'px');
	}

	CssClass.prototype.setHeight = function setHeight(value) {
		this.height = value;
		this.node.style.height = this.height + 'px';
		OutputManager.updateProperty(this.id, 'height', this.height + 'px');
	}

	// Browser support
	CssClass.prototype.setRotate = function setRotate(value) {
		var cssvalue = 'rotate(' + value +'deg)';

		this.node.style.transform = cssvalue;
		this.node.style.webkitTransform = cssvalue;
		this.node.style.msTransform = cssvalue;

		if (value !== 0) {
			if (this.rotate === 0) {
				OutputManager.toggleProperty(this.id, 'transform', true);
				OutputManager.toggleProperty(this.id, '-webkit-transform', true);
				OutputManager.toggleProperty(this.id, '-ms-transform', true);
			}
		}
		else {
			OutputManager.toggleProperty(this.id, 'transform', false);
			OutputManager.toggleProperty(this.id, '-webkit-transform', false);
			OutputManager.toggleProperty(this.id, '-ms-transform', false);
		}

		OutputManager.updateProperty(this.id, 'transform', cssvalue);
		OutputManager.updateProperty(this.id, '-webkit-transform', cssvalue);
		OutputManager.updateProperty(this.id, '-ms-transform', cssvalue);
		this.rotate = value;
	}

	CssClass.prototype.setzIndex = function setzIndex(value) {
		this.node.style.zIndex = value;
		OutputManager.updateProperty(this.id, 'z-index', value);
		this.zIndex = value;
	}

	CssClass.prototype.toggleDisplay = function toggleDisplay(value) {
		if (typeof value !== "boolean" || this.display === value)
			return;

		this.display = value;
		var display = this.display === true ? "block" : "none";
		this.node.style.display = display;
		this.object.style.display = display;
	}

	CssClass.prototype.toggleBorder = function toggleBorder(value) {
		if (typeof value !== "boolean" || this.border === value)
			return;

		this.border = value;
		var border = this.border === true ? "1px solid #CCC" : "none";
		this.node.style.border = border;
	}

	CssClass.prototype.updateBgColor = function updateBgColor(color) {
		this.bgcolor.copy(color);
		this.node.style.backgroundColor = color.getColor();
		OutputManager.updateProperty(this.id, 'background-color', color.getColor());
	}

	CssClass.prototype.updateShadows = function updateShadows() {
		if (this.render.length === 0)
			OutputManager.toggleProperty(this.id, 'box-shadow', false);
		if (this.render.length === 1)
			OutputManager.toggleProperty(this.id, 'box-shadow', true);

		this.node.style.boxShadow = this.render.join(", ");
		OutputManager.updateProperty(this.id, 'box-shadow', this.render.join(", \n"));

	}


	/**
	 * Tool Manager
	 */
	var Tool = (function Tool() {

		var preview;
		var classes = [];
		var active = null;
		var animate = false;

		/*
		 * Toll actions
		 */
		var addCssClass = function addCssClass(id) {
			classes[id] = new CssClass(id);
		}

		var setActiveClass = function setActiveClass(id) {
			active = classes[id];
			active.shadowID = null;
			ColoPicker.setColor(classes[id].bgcolor);
			SliderManager.setValue("top", active.top);
			SliderManager.setValue("left", active.left);
			SliderManager.setValue("rotate", active.rotate);
			SliderManager.setValue("z-index", active.zIndex);
			SliderManager.setValue("width", active.width);
			SliderManager.setValue("height", active.height);
			ButtonManager.setValue("border-state", active.border);
			active.updateShadows();
		}

		var disableClass = function disableClass(topic) {
			classes[topic].toggleDisplay(false);
			ButtonManager.setValue(topic, false);
		}

		var addShadow = function addShadow(position) {
			if (animate === true)
				return -1;

			active.shadows.splice(position, 0, new Shadow());
			active.render.splice(position, 0, null);
		}

		var swapShadow = function swapShadow(id1, id2) {
			var x = active.shadows[id1];
			active.shadows[id1] = active.shadows[id2];
			active.shadows[id2] = x;
			updateShadowCSS(id1);
			updateShadowCSS(id2);
		}

		var deleteShadow = function deleteShadow(position) {
			active.shadows.splice(position, 1);
			active.render.splice(position, 1);
			active.updateShadows();
		}

		var setActiveShadow = function setActiveShadow(id, glow) {
			active.shadowID = id;
			ColoPicker.setColor(active.shadows[id].color);
			ButtonManager.setValue("inset", active.shadows[id].inset);
			SliderManager.setValue("blur", active.shadows[id].blur);
			SliderManager.setValue("spread", active.shadows[id].spread);
			SliderManager.setValue("posX", active.shadows[id].posX);
			SliderManager.setValue("posY", active.shadows[id].posY);
			if (glow === true)
				addGlowEffect(id);
		}

		var addGlowEffect = function addGlowEffect(id) {
			if (animate === true)
				return;

			animate = true;
			var store = new Shadow();
			var shadow = active.shadows[id];

			store.copy(shadow);
			shadow.color.setRGBA(40, 125, 200, 1);
			shadow.blur = 10;
			shadow.spread = 10;

			active.node.style.transition = "box-shadow 0.2s";
			updateShadowCSS(id);

			setTimeout(function() {
				shadow.copy(store);
				updateShadowCSS(id);
				setTimeout(function() {
					active.node.style.removeProperty("transition");
					animate = false;
				}, 100);
			}, 200);
		}

		var updateActivePos = function updateActivePos(deltaX, deltaY) {
			if (active.shadowID === null)
				active.updatePos(deltaX, deltaY);
			else
				updateShadowPos(deltaX, deltaY);
		}

		/*
		 * Shadow properties
		 */
		var updateShadowCSS = function updateShadowCSS(id) {
			active.render[id] = active.shadows[id].computeCSS();
			active.updateShadows();
		}

		var toggleShadowInset = function toggleShadowInset(value) {
			if (active.shadowID === null)
				return;
			active.shadows[active.shadowID].toggleInset(value);
			updateShadowCSS(active.shadowID);
		}

		var updateShadowPos = function updateShadowPos(deltaX, deltaY) {
			var shadow = active.shadows[active.shadowID];
			shadow.posX += deltaX;
			shadow.posY += deltaY;
			SliderManager.setValue("posX", shadow.posX);
			SliderManager.setValue("posY", shadow.posY);
			updateShadowCSS(active.shadowID);
		}

		var setShadowPosX = function setShadowPosX(value) {
			if (active.shadowID === null)
				return;
			active.shadows[active.shadowID].posX = value;
			updateShadowCSS(active.shadowID);
		}

		var setShadowPosY = function setShadowPosY(value) {
			if (active.shadowID === null)
				return;
			active.shadows[active.shadowID].posY = value;
			updateShadowCSS(active.shadowID);
		}

		var setShadowBlur = function setShadowBlur(value) {
			if (active.shadowID === null)
				return;
			active.shadows[active.shadowID].blur = value;
			updateShadowCSS(active.shadowID);
		}

		var setShadowSpread = function setShadowSpread(value) {
			if (active.shadowID === null)
				return;
			active.shadows[active.shadowID].spread = value;
			updateShadowCSS(active.shadowID);
		}

		var updateShadowColor = function updateShadowColor(color) {
			active.shadows[active.shadowID].color.copy(color);
			updateShadowCSS(active.shadowID);
		}

		/*
		 * Element Properties
		 */
		var updateColor = function updateColor(color) {
			if (active.shadowID === null)
				active.updateBgColor(color);
			else
				updateShadowColor(color);
		}

		var init = function init() {
			preview = getElemById("preview");

			ColoPicker.subscribe("color", updateColor);
			PreviewMouseTracking.subscribe(updateActivePos);

			// Affects shadows
			ButtonManager.subscribe("inset", toggleShadowInset);
			SliderManager.subscribe("posX", setShadowPosX);
			SliderManager.subscribe("posY", setShadowPosY);
			SliderManager.subscribe("blur", setShadowBlur);
			SliderManager.subscribe("spread", setShadowSpread);

			// Affects element
			SliderManager.subscribe("top", function(value){
				active.setTop(value);
			});
			SliderManager.subscribe("left", function(value){
				active.setLeft(value);
			});
			SliderManager.subscribe("rotate", function(value) {
				if (active == classes["element"])
					return;
				active.setRotate(value);
			});

			SliderManager.subscribe("z-index", function(value) {
				if (active == classes["element"])
					return;
				active.setzIndex(value);
			});

			SliderManager.subscribe("width", function(value) {
				active.setWidth(value)
			});

			SliderManager.subscribe("height", function(value) {
				active.setHeight(value)
			});

			// Actions
			classes['before'].top = -30;
			classes['before'].left = -30;
			classes['after'].top = 30;
			classes['after'].left = 30;
			classes['before'].toggleDisplay(false);
			classes['after'].toggleDisplay(false);
			ButtonManager.setValue('before', false);
			ButtonManager.setValue('after', false);

			ButtonManager.subscribe("before", classes['before'].toggleDisplay.bind(classes['before']));
			ButtonManager.subscribe("after", classes['after'].toggleDisplay.bind(classes['after']));

			ButtonManager.subscribe("border-state", function(value) {
				active.toggleBorder(value);
			});

		}

		return {
			init 			: init,
			addShadow		: addShadow,
			swapShadow		: swapShadow,
			addCssClass		: addCssClass,
			disableClass	: disableClass,
			deleteShadow	: deleteShadow,
			setActiveClass	: setActiveClass,
			setActiveShadow : setActiveShadow
		}

	})();

	/**
	 * Layer Manager
	 */
	var LayerManager = (function LayerManager() {
		var stacks = [];
		var active = {
			node : null,
			stack : null
		}
		var elements = {};

		var mouseEvents = function mouseEvents(e) {
			var node = e.target;
			var type = node.getAttribute('data-type');

			if (type === 'subject')
				setActiveStack(stacks[node.id]);

			if (type === 'disable') {
				Tool.disableClass(node.parentNode.id);
				setActiveStack(stacks['element']);
			}

			if (type === 'add')
				active.stack.addLayer();

			if (type === 'layer')
				active.stack.setActiveLayer(node);

			if (type === 'delete')
				active.stack.deleteLayer(node.parentNode);

			if (type === 'move-up')
				active.stack.moveLayer(1);

			if (type === 'move-down')
				active.stack.moveLayer(-1);
		}

		var setActiveStack = function setActiveStack(stackObj) {
			active.stack.hide();
			active.stack = stackObj;
			active.stack.show();
		}

		/*
		 * Stack object
		 */
		var Stack = function Stack(subject) {
			var S = document.createElement('div');
			var title = document.createElement('div');
			var stack = document.createElement('div');

			S.className = 'container';
			stack.className = 'stack';
			title.className = 'title';
			title.textContent = subject.getAttribute('data-title');
			S.appendChild(title);
			S.appendChild(stack);

			this.id = subject.id;
			this.container = S;
			this.stack = stack;
			this.subject = subject;
			this.order = [];
			this.uid = 0;
			this.count = 0;
			this.layer = null;
			this.layerID = 0;
		}

		Stack.prototype.addLayer = function addLayer() {
			if (Tool.addShadow(this.layerID) == -1)
				return;

			var uid = this.getUID();
			var layer = this.createLayer(uid);

			if (this.layer === null && this.stack.children.length >= 1)
				this.layer = this.stack.children[0];

			this.stack.insertBefore(layer, this.layer);
			this.order.splice(this.layerID, 0, uid);
			this.count++;
			this.setActiveLayer(layer);
		}

		Stack.prototype.createLayer = function createLayer(uid) {
			var layer = document.createElement('div');
			var del = document.createElement('span');

			layer.className = 'node';
			layer.setAttribute('data-shid', uid);
			layer.setAttribute('data-type', 'layer');
			layer.textContent = 'shadow ' + uid;

			del.className = 'delete';
			del.setAttribute('data-type', 'delete');

			layer.appendChild(del);
			return layer;
		}

		Stack.prototype.getUID = function getUID() {
			return this.uid++;
		}

		// SOLVE IE BUG
		Stack.prototype.moveLayer = function moveLayer(direction) {
			if (this.count <= 1 || this.layer === null)
				return;
			if (direction === -1 && this.layerID === (this.count - 1) )
				return;
			if (direction === 1 && this.layerID === 0 )
				return;

			if (direction === -1) {
				var before = null;
				Tool.swapShadow(this.layerID, this.layerID + 1);
				this.swapOrder(this.layerID, this.layerID + 1);
				this.layerID += 1;

				if (this.layerID + 1 !== this.count)
					before = this.stack.children[this.layerID + 1];

				this.stack.insertBefore(this.layer, before);
				Tool.setActiveShadow(this.layerID, false);
			}

			if (direction === 1) {
				Tool.swapShadow(this.layerID, this.layerID - 1);
				this.swapOrder(this.layerID, this.layerID - 1);
				this.layerID -= 1;
				this.stack.insertBefore(this.layer, this.stack.children[this.layerID]);
				Tool.setActiveShadow(this.layerID, false);
			}
		}

		Stack.prototype.swapOrder = function swapOrder(pos1, pos2) {
			var x = this.order[pos1];
			this.order[pos1] = this.order[pos2];
			this.order[pos2] = x;
		}

		Stack.prototype.deleteLayer = function deleteLayer(node) {
			var shadowID =  node.getAttribute('data-shid') | 0;
			var index = this.order.indexOf(shadowID);
			this.stack.removeChild(this.stack.children[index]);
			this.order.splice(index, 1);
			this.count--;

			Tool.deleteShadow(index);

			if (index > this.layerID)
				return;

			if (index == this.layerID) {
				if (this.count >= 1) {
					this.layerID = 0;
					this.setActiveLayer(this.stack.children[0], true);
				}
				else {
					this.layer = null;
					this.show();
				}
			}

			if (index < this.layerID) {
				this.layerID--;
				Tool.setActiveShadow(this.layerID, true);
			}

		}

		Stack.prototype.setActiveLayer = function setActiveLayer(node) {
			elements.shadow_properties.style.display = 'block';
			elements.element_properties.style.display = 'none';

			if (this.layer)
				this.layer.removeAttribute('data-active');

			this.layer = node;
			this.layer.setAttribute('data-active', 'layer');

			var shadowID =  node.getAttribute('data-shid') | 0;
			this.layerID = this.order.indexOf(shadowID);
			Tool.setActiveShadow(this.layerID, true);
		}

		Stack.prototype.unsetActiveLayer = function unsetActiveLayer() {
			if (this.layer)
				this.layer.removeAttribute('data-active');

			this.layer = null;
			this.layerID = 0;
		}

		Stack.prototype.hide = function hide() {
			this.unsetActiveLayer();
			this.subject.removeAttribute('data-active');
			var style = this.container.style;
			style.left = '100%';
			style.zIndex = '0';
		}

		Stack.prototype.show = function show() {
			elements.shadow_properties.style.display = 'none';
			elements.element_properties.style.display = 'block';

			if (this.id === 'element') {
				elements.zIndex.style.display = 'none';
				elements.transform_rotate.style.display = 'none';
			}
			else {
				elements.zIndex.style.display = 'block';
				elements.transform_rotate.style.display = 'block';
			}

			this.subject.setAttribute('data-active', 'subject');
			var style = this.container.style;
			style.left = '0';
			style.zIndex = '10';
			Tool.setActiveClass(this.id);
		}

		function init() {

			var elem, size;
			var layerManager = getElemById("layer_manager");
			var layerMenu = getElemById("layer_menu");
			var container = getElemById("stack_container");

			elements.shadow_properties = getElemById('shadow_properties');
			elements.element_properties = getElemById('element_properties');
			elements.transform_rotate = getElemById('transform_rotate');
			elements.zIndex = getElemById('z-index');

			elem = document.querySelectorAll('#layer_menu [data-type="subject"]');
			size = elem.length;

			for (var i = 0; i < size; i++) {
				var S = new Stack(elem[i]);
				stacks[elem[i].id] = S;
				container.appendChild(S.container);
				Tool.addCssClass(elem[i].id);
			}

			active.stack = stacks['element'];
			stacks['element'].show();

			layerManager.addEventListener("click", mouseEvents);
			layerMenu.addEventListener("click", mouseEvents);

			ButtonManager.subscribe("before", function(value) {
				if (value === false && active.stack === stacks['before'])
					setActiveStack(stacks['element'])
				if (value === true && active.stack !== stacks['before'])
					setActiveStack(stacks['before'])
			});

			ButtonManager.subscribe("after", function(value) {
				if (value === false && active.stack === stacks['after'])
					setActiveStack(stacks['element'])
				if (value === true && active.stack !== stacks['after'])
					setActiveStack(stacks['after'])
			});
		}

		return {
			init : init
		}
	})();

	/*
	 * OutputManager
	 */
	var OutputManager = (function OutputManager() {
		var classes = [];
		var buttons = [];
		var active = null;
		var menu = null;
		var button_offset = 0;

		var crateOutputNode = function(topic, property) {

			var prop = document.createElement('div');
			var name = document.createElement('span');
			var value = document.createElement('span');

			var pmatch = property.match(/(^([a-z0-9\-]*)=\[([a-z0-9\-\"]*)\])|^([a-z0-9\-]*)/i);

			name.textContent = '\t' + pmatch[4];

			if (pmatch[3] !== undefined) {
				name.textContent = '\t' + pmatch[2];
				value.textContent = pmatch[3] + ';';
			}

			name.textContent += ': ';
			prop.className = 'css-property';
			name.className = 'name';
			value.className = 'value';
			prop.appendChild(name);
			prop.appendChild(value);

			classes[topic].node.appendChild(prop);
			classes[topic].line[property] = prop;
			classes[topic].prop[property] = value;
		}

		var OutputClass = function OutputClass(node) {
			var topic = node.getAttribute('data-topic');
			var prop = node.getAttribute('data-prop');
			var name = node.getAttribute('data-name');
			var properties = prop.split(' ');

			classes[topic] = {};
			classes[topic].node = node;
			classes[topic].prop = [];
			classes[topic].line = [];
			classes[topic].button = new Button(topic);

			var open_decl = document.createElement('div');
			var end_decl = document.createElement('div');

			open_decl.textContent = name + ' {';
			end_decl.textContent = '}';
			node.appendChild(open_decl);

			for (var i in properties)
				crateOutputNode(topic, properties[i]);

			node.appendChild(end_decl);
		}

		var Button = function Button(topic) {
			var button = document.createElement('div');

			button.className = 'button';
			button.textContent = topic;
			button.style.left = button_offset + 'px';
			button_offset += 100;

			button.addEventListener("click", function() {
				toggleDisplay(topic);
			})

			menu.appendChild(button);
			return button;
		}

		var toggleDisplay = function toggleDisplay(topic) {
			active.button.removeAttribute('data-active');
			active.node.style.display = 'none';
			active = classes[topic];
			active.node.style.display = 'block';
			active.button.setAttribute('data-active', 'true');
		}

		var toggleButton = function toggleButton(topic, value) {
			var display = (value === true) ? 'block' : 'none';
			classes[topic].button.style.display = display;

			if (value === true)
				toggleDisplay(topic);
			else
				toggleDisplay('element');
		}

		var updateProperty = function updateProperty(topic, property, data) {
			try {
				classes[topic].prop[property].textContent = data + ';';
			}
			catch(error) {
				// console.log("ERROR undefined : ", topic, property, data);
			}
		}

		var toggleProperty = function toggleProperty(topic, property, value) {
			var display = (value === true) ? 'block' : 'none';
			try {
				classes[topic].line[property].style.display = display;
			}
			catch(error) {
				// console.log("ERROR undefined : ",classes, topic, property, value);
			}
		}

		var init = function init() {

			menu = getElemById('menu');

			var elem = document.querySelectorAll('#output .output');
			var size = elem.length;
			for (var i = 0; i < size; i++)
				OutputClass(elem[i]);

			active = classes['element'];
			toggleDisplay('element');

			ButtonManager.subscribe("before", function(value) {
				toggleButton('before', value);
			});

			ButtonManager.subscribe("after", function(value) {
				toggleButton('after', value);
			});
		}

		return {
			init : init,
			updateProperty : updateProperty,
			toggleProperty : toggleProperty
		}

	})();


	/**
	 * Init Tool
	 */
	var init = function init() {
		ButtonManager.init();
		OutputManager.init();
		ColoPicker.init();
		SliderManager.init();
		LayerManager.init();
		PreviewMouseTracking.init("preview");
		Tool.init();
	}

	return {
		init : init
	}

})();


 

Document Tags and Contributors

 Contributors to this page: teoli, Sheppy, gabriel_ivanica, groovecoder
 Last updated by: Sheppy,