<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[19995] trunk/wp-includes: Introduce new theme customizer to replace theme preview.</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg > ul, #logmsg > ol { margin-left: 0; margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/19995">19995</a></dd>
<dt>Author</dt> <dd>koopersmith</dd>
<dt>Date</dt> <dd>2012-02-25 04:12:43 +0000 (Sat, 25 Feb 2012)</dd>
</dl>
<h3>Log Message</h3>
<pre>Introduce new theme customizer to replace theme preview. Rough first pass. props koopersmith, ocean90. see <a href="http://core.trac.wordpress.org/ticket/19910">#19910</a>.
Merges in http://plugins.svn.wordpress.org/gandalf/branches/dev/ <a href="http://core.trac.wordpress.org/changeset/510148">rev 510148</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpincludesscriptloaderphp">trunk/wp-includes/script-loader.php</a></li>
<li><a href="#trunkwpincludesthemephp">trunk/wp-includes/theme.php</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkwpincludesclasswpcustomizesectionphp">trunk/wp-includes/class-wp-customize-section.php</a></li>
<li><a href="#trunkwpincludesclasswpcustomizesettingphp">trunk/wp-includes/class-wp-customize-setting.php</a></li>
<li><a href="#trunkwpincludesclasswpcustomizephp">trunk/wp-includes/class-wp-customize.php</a></li>
<li><a href="#trunkwpincludescsscustomizecontrolscss">trunk/wp-includes/css/customize-controls.css</a></li>
<li><a href="#trunkwpincludescsscustomizecontrolsdevcss">trunk/wp-includes/css/customize-controls.dev.css</a></li>
<li><a href="#trunkwpincludescsscustomizeloadercss">trunk/wp-includes/css/customize-loader.css</a></li>
<li><a href="#trunkwpincludescsscustomizeloaderdevcss">trunk/wp-includes/css/customize-loader.dev.css</a></li>
<li><a href="#trunkwpincludescustomizecontrolsphp">trunk/wp-includes/customize-controls.php</a></li>
<li><a href="#trunkwpincludesjscustomizebasedevjs">trunk/wp-includes/js/customize-base.dev.js</a></li>
<li><a href="#trunkwpincludesjscustomizebasejs">trunk/wp-includes/js/customize-base.js</a></li>
<li><a href="#trunkwpincludesjscustomizecontrolsdevjs">trunk/wp-includes/js/customize-controls.dev.js</a></li>
<li><a href="#trunkwpincludesjscustomizecontrolsjs">trunk/wp-includes/js/customize-controls.js</a></li>
<li><a href="#trunkwpincludesjscustomizeloaderdevjs">trunk/wp-includes/js/customize-loader.dev.js</a></li>
<li><a href="#trunkwpincludesjscustomizeloaderjs">trunk/wp-includes/js/customize-loader.js</a></li>
<li><a href="#trunkwpincludesjscustomizepreviewdevjs">trunk/wp-includes/js/customize-preview.dev.js</a></li>
<li><a href="#trunkwpincludesjscustomizepreviewjs">trunk/wp-includes/js/customize-preview.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpincludesclasswpcustomizesectionphp"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/class-wp-customize-section.php (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/class-wp-customize-section.php         (rev 0)
+++ trunk/wp-includes/class-wp-customize-section.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+<?php
+/**
+ * Customize Section Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+
+class WP_Customize_Section {
+        public $id;
+        public $priority = 10;
+        public $capability = 'edit_theme_options';
+        public $theme_supports = '';
+        public $title = '';
+        public $description = '';
+        public $settings;
+
+        /**
+         * Constructor.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the section.
+         * @param array $args Section arguments.
+         */
+        function __construct( $id, $args = array() ) {
+                $this->id = $id;
+
+                $keys = array_keys( get_class_vars( __CLASS__ ) );
+                foreach ( $keys as $key ) {
+                        if ( isset( $args[ $key ] ) )
+                                $this->$key = $args[ $key ];
+                }
+
+                $this->settings = array(); // Users cannot customize the $settings array.
+
+                return $this;
+        }
+
+        /**
+         * Check if the theme supports the section and check user capabilities.
+         *
+         * @since 3.4.0
+         *
+         * @return bool False if theme doesn't support the section or user doesn't have the capability.
+         */
+        function check_capabilities() {
+                if ( ! $this->capability || ! current_user_can( $this->capability ) )
+                        return false;
+
+                if ( $this->theme_supports && ! current_theme_supports( $this->theme_supports ) )
+                        return false;
+
+                return true;
+        }
+
+        /**
+         * Render the section.
+         *
+         * @since 3.4.0
+         */
+        function render() {
+                if ( ! $this->check_capabilities() )
+                        return;
+                ?>
+                <li id="customize-section-<?php echo esc_attr( $this->id ); ?>" class="control-section customize-section">
+                        <h3 class="customize-theme-title"><?php echo esc_html( $this->title ); ?></h3>
+                        <ul>
+                                <?php if ( $this->description ) : ?>
+                                        <li><p class="howto"><?php echo $this->description; ?></p></li>
+                                <?php endif; ?>
+
+                                <?php foreach ( $this->settings as $setting ) : ?>
+                                <li>
+                                        <?php $setting->_render(); ?>
+                                </li>
+                                <?php endforeach; ?>
+                        </ul>
+                </li>
+                <?php
+        }
+}
</ins></span></pre></div>
<a id="trunkwpincludesclasswpcustomizesettingphp"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/class-wp-customize-setting.php (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/class-wp-customize-setting.php         (rev 0)
+++ trunk/wp-includes/class-wp-customize-setting.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,489 @@
</span><ins>+<?php
+/**
+ * Customize Setting Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+
+class WP_Customize_Setting {
+        public $id;
+        public $priority = 10;
+        public $section = '';
+        public $label = '';
+        public $control = 'text';
+        public $type = 'theme_mod';
+        public $choices = array();
+        public $capability = 'edit_theme_options';
+        public $theme_supports = '';
+        public $default = '';
+        public $sanitize_callback = '';
+
+        protected $id_data = array();
+        private $_post_value; // Cached, sanitized $_POST value.
+
+        // Prefix for $_POST values to prevent naming conflicts.
+        const name_prefix = 'customize_';
+
+        /**
+         * Constructor.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the setting. Can be a
+         * theme mod or option name.
+         * @param array $args Setting arguments.
+         */
+        function __construct( $id, $args = array() ) {
+                $keys = array_keys( get_class_vars( __CLASS__ ) );
+                foreach ( $keys as $key ) {
+                        if ( isset( $args[ $key ] ) )
+                                $this->$key = $args[ $key ];
+                }
+
+                $this->id = $id;
+
+                // Parse the ID for array keys.
+                $this->id_data[ 'keys' ] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
+                $this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys' ] );
+
+                // Rebuild the ID.
+                $this->id = $this->id_data[ 'base' ];
+                if ( ! empty( $this->id_data[ 'keys' ] ) )
+                        $this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']';
+
+                if ( $this->sanitize_callback != '' )
+                        add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback );
+
+                return $this;
+        }
+
+        /**
+         * Enqueue setting related scripts/styles.
+         *
+         * @since 3.4.0
+         */
+        public function enqueue() {
+                switch( $this->control ) {
+                        case 'color':
+                                wp_enqueue_script( 'farbtastic' );
+                                wp_enqueue_style( 'farbtastic' );
+                                break;
+                }
+        }
+
+        /**
+         * Handle previewing the setting.
+         *
+         * @since 3.4.0
+         */
+        public function preview() {
+                switch( $this->type ) {
+                        case 'theme_mod' :
+                                add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+                                break;
+                        case 'option' :
+                                if ( empty( $this->id_data[ 'keys' ] ) )
+                                        add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+                                else
+                                        add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+                                break;
+                        default :
+                                do_action( 'customize_preview_' . $this->id );
+                }
+        }
+
+        /**
+         * Callback function to filter the theme mods and options.
+         *
+         * @since 3.4.0
+         *
+         * @param mixed Old value.
+         * @return mixed New or old value.
+         */
+        public function _preview_filter( $original ) {
+                return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
+        }
+
+        /**
+         * Set the value of the parameter for a specific theme.
+         *
+         * @since 3.4.0
+         *
+         * @return bool False if cap check fails or value isn't set.
+         */
+        public final function save() {
+                $value = $this->post_value();
+
+                if ( ! $this->check_capabilities() || ! isset( $value ) )
+                        return false;
+
+                do_action( 'customize_save_' . $this->id_data[ 'base' ] );
+
+                $this->update( $value );
+        }
+
+        /**
+         * Fetches, validates, and sanitizes the $_POST value.
+         *
+         * @since 3.4.0
+         *
+         * @param $default mixed A default value which is used as a fallback. Default is null.
+         * @return mixed Either the default value on failure or sanitized value.
+         */
+        public final function post_value( $default = null ) {
+                if ( isset( $this->_post_value ) )
+                        return $this->_post_value;
+
+                $base = self::name_prefix . $this->id_data[ 'base' ];
+
+                if ( ! isset( $_POST[ $base ] ) )
+                        return $default;
+
+                $result = $this->multidimensional_get( $_POST[ $base ], $this->id_data[ 'keys' ] );
+                if ( ! isset( $result ) )
+                        return $default;
+
+                $result = $this->sanitize( $result );
+                if ( isset( $result ) )
+                        return $this->_post_value = $result;
+                else
+                        return $default;
+        }
+
+        /**
+         * Sanitize an input.
+         *
+         * @since 3.4.0
+         *
+         * @param $value mixed The value to sanitize.
+         * @return mixed Null if an input isn't valid, otherwise the sanitized value.
+         */
+        public function sanitize( $value ) {
+                return apply_filters( "customize_sanitize_{$this->id}", $value );
+        }
+
+        /**
+         * Set the value of the parameter for a specific theme.
+         *
+         * @since 3.4.0
+         *
+         * @param $value mixed The value to update.
+         * @return mixed The result of saving the value.
+         */
+        protected function update( $value ) {
+                switch( $this->type ) {
+                        case 'theme_mod' :
+                                return $this->_update_theme_mod( $value );
+                                break;
+                        case 'option' :
+                                return $this->_update_option( $value );
+                                break;
+                        default :
+                                return do_action( 'customize_update_' . $this->type, $value );
+                }
+        }
+
+        /**
+         * Update the theme mod from the value of the parameter.
+         *
+         * @since 3.4.0
+         *
+         * @param $value mixed The value to update.
+         * @return mixed The result of saving the value.
+         */
+        protected function _update_theme_mod( $value ) {
+                // Handle non-array theme mod.
+                if ( empty( $this->id_data[ 'keys' ] ) )
+                        return set_theme_mod( $this->id_data[ 'base' ], $value );
+
+                // Handle array-based theme mod.
+                $mods = get_theme_mod( $this->id_data[ 'base' ] );
+                $mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value );
+                if ( isset( $mods ) )
+                        return set_theme_mod( $this->id_data[ 'base' ], $mods );
+        }
+
+        /**
+         * Update the theme mod from the value of the parameter.
+         *
+         * @since 3.4.0
+         *
+         * @param $value mixed The value to update.
+         * @return mixed The result of saving the value.
+         */
+        protected function _update_option( $value ) {
+                // Handle non-array option.
+                if ( empty( $this->id_data[ 'keys' ] ) )
+                        return update_option( $this->id_data[ 'base' ], $value );
+
+                // Handle array-based options.
+                $options = get_option( $this->id_data[ 'base' ] );
+                $options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value );
+                if ( isset( $options ) )
+                        return update_option( $this->id_data[ 'base' ], $options );
+        }
+
+        /**
+         * Fetch the value of the parameter for a specific theme.
+         *
+         * @since 3.4.0
+         *
+         * @return mixed The requested value.
+         */
+        public function value() {
+                switch( $this->type ) {
+                        case 'theme_mod' :
+                                $function = 'get_theme_mod';
+                                break;
+                        case 'option' :
+                                $function = 'get_option';
+                                break;
+                        default :
+                                return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
+                }
+
+                // Handle non-array value
+                if ( empty( $this->id_data[ 'keys' ] ) )
+                        return $function( $this->id_data[ 'base' ], $this->default );
+
+                // Handle array-based value
+                $values = $function( $this->id_data[ 'base' ] );
+                return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default );
+        }
+
+        /**
+         * Check if the theme supports the setting and check user capabilities.
+         *
+         * @since 3.4.0
+         *
+         * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
+         */
+        public final function check_capabilities() {
+                global $customize;
+
+                if ( ! $this->capability || ! current_user_can( $this->capability ) )
+                        return false;
+
+                if ( $this->theme_supports && ! current_theme_supports( $this->theme_supports ) )
+                        return false;
+
+                $section = $customize->get_section( $this->section );
+                if ( isset( $section ) && ! $section->check_capabilities() )
+                        return false;
+
+                return true;
+        }
+
+        /**
+         * Render the control.
+         *
+         * @since 3.4.0
+         */
+        public final function _render() {
+                if ( ! $this->check_capabilities() )
+                        return;
+
+                do_action( 'customize_render_' . $this->id );
+
+                $this->render();
+        }
+
+        /**
+         * Render the control.
+         *
+         * @since 3.4.0
+         */
+        protected function render() {
+                $this->_render_type();
+        }
+
+        /**
+         * Retrieve the name attribute for an input.
+         *
+         * @since 3.4.0
+         *
+         * @return string The name.
+         */
+        public final function get_name() {
+                return self::name_prefix . esc_attr( $this->id );
+        }
+
+        /**
+         * Echo the HTML name attribute for an input.
+         *
+         * @since 3.4.0
+         *
+         * @return string The HTML name attribute.
+         */
+        public final function name() {
+                echo 'name="' . $this->get_name() . '"';
+        }
+
+        /**
+         * Render the control type.
+         *
+         * @todo Improve value and checked attributes.
+         *
+         * @since 3.4.0
+         */
+        public final function _render_type() {
+                switch( $this->control ) {
+                        case 'text':
+                                ?>
+                                <label><?php echo esc_html( $this->label ); ?><br/>
+                                        <input type="text" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->name(); ?> />
+                                </label>
+                                <?php
+                                break;
+                        case 'color':
+                                ?>
+                                <label><?php echo esc_html( $this->label ); ?><br/>
+                                        <span class="hex-prepend">#</span>
+                                        <input type="text" class="hex-input" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->name(); ?> />
+                                        <a href="#" class="pickcolor hex-color-example"></a>
+                                </label>
+                                <?php
+                                break;
+                        case 'checkbox':
+                                ?>
+                                <label>
+                                        <input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->name(); checked( $this->value() ); ?> />
+                                        <?php echo esc_html( $this->label ); ?>
+                                </label>
+                                <?php
+                                break;
+                        case 'radio':
+                                if ( empty( $this->choices ) )
+                                        return;
+
+                                echo esc_html( $this->label ) . '<br/>';
+                                foreach ( $this->choices as $value => $label ) :
+                                        ?>
+                                        <label>
+                                                <input type="radio" value="<?php echo esc_attr( $value ); ?>" <?php $this->name(); checked( $this->value(), $value ); ?> />
+                                                <?php echo esc_html( $label ); ?><br/>
+                                        </label>
+                                        <?php
+                                endforeach;
+                                break;
+                        case 'select':
+                                if ( empty( $this->choices ) )
+                                        return;
+
+                                ?>
+                                <label><?php echo esc_html( $this->label ); ?><br/>
+                                <select <?php $this->name(); ?>>
+                                        <?php
+                                        foreach ( $this->choices as $value => $label )
+                                                echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
+                                        ?>
+                                </select>
+                                <?php
+                                break;
+                        default:
+                                do_action( 'customize_render_control-' . $this->control, $this );
+
+                }
+        }
+
+        /**
+         * Multidimensional helper function.
+         *
+         * @since 3.4.0
+         *
+         * @param $root
+         * @param $keys
+         * @param bool $create Default is false.
+         * @return null|array
+         */
+        final protected function multidimensional( $root, $keys, $create = false ) {
+                if ( $create && empty( $root ) )
+                        $root = array();
+
+                if ( ! isset( $root ) || empty( $keys ) )
+                        return;
+
+                $last = array_pop( $keys );
+                $node = &$root;
+
+                foreach ( $keys as $key ) {
+                        if ( $create && ! isset( $node[ $key ] ) )
+                                $node[ $key ] = array();
+
+                        if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
+                                return;
+
+                        $node = &$node[ $key ];
+                }
+
+                if ( $create && ! isset( $node[ $last ] ) )
+                        $node[ $last ] = array();
+
+                if ( ! isset( $node[ $last ] ) )
+                        return;
+
+                return array(
+                        'root' => &$root,
+                        'node' => &$node,
+                        'key' => $last,
+                );
+        }
+
+        /**
+         * Will attempt to replace a specific value in a multidimensional array.
+         *
+         * @since 3.4.0
+         *
+         * @param $root
+         * @param $keys
+         * @param mixed $value The value to update.
+         * @return
+         */
+        final protected function multidimensional_replace( $root, $keys, $value ) {
+                if ( ! isset( $value ) )
+                        return $root;
+                elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
+                        return $value;
+
+                $result = $this->multidimensional( &$root, $keys, true );
+
+                if ( isset( $result ) )
+                        $result['node'][ $result['key'] ] = $value;
+
+                return $root;
+        }
+
+        /**
+         * Will attempt to fetch a specific value from a multidimensional array.
+         *
+         * @since 3.4.0
+         *
+         * @param $root
+         * @param $keys
+         * @param $default A default value which is used as a fallback. Default is null.
+         * @return mixed The requested value or the default value.
+         */
+        final protected function multidimensional_get( $root, $keys, $default = null ) {
+                if ( empty( $keys ) ) // If there are no keys, test the root.
+                        return isset( $root ) ? $root : $default;
+
+                $result = $this->multidimensional( $root, $keys );
+                return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
+        }
+
+        /**
+         * Will attempt to check if a specific value in a multidimensional array is set.
+         *
+         * @since 3.4.0
+         *
+         * @param $root
+         * @param $keys
+         * @return bool True if value is set, false if not.
+         */
+        final protected function multidimensional_isset( $root, $keys ) {
+                $result = $this->multidimensional_get( $root, $keys );
+                return isset( $result );
+        }
+}
</ins></span></pre></div>
<a id="trunkwpincludesclasswpcustomizephp"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/class-wp-customize.php (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/class-wp-customize.php         (rev 0)
+++ trunk/wp-includes/class-wp-customize.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,660 @@
</span><ins>+<?php
+/**
+ * Customize
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+
+final class WP_Customize {
+        protected $template;
+        protected $stylesheet;
+        protected $previewing = false;
+
+        protected $settings = array();
+        protected $sections = array();
+
+        /**
+         * Constructor.
+         *
+         * @since 3.4.0
+         */
+        public function __construct() {
+                require( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
+                require( ABSPATH . WPINC . '/class-wp-customize-section.php' );
+
+                add_action( 'setup_theme', array( $this, 'setup_theme' ) );
+                add_action( 'admin_init', array( $this, 'admin_init' ) );
+                add_action( 'init', array( $this, 'init' ) );
+                add_action( 'admin_footer', array( $this, 'admin_footer' ) );
+
+                add_action( 'customize_previewing', array( $this, 'customize_previewing' ) );
+                add_action( 'customize_register', array( $this, 'register_controls' ) );
+                add_action( 'customize_controls_init', array( $this, 'prepare_controls' ) );
+        }
+
+        /**
+         * Update theme modifications for the current theme.
+         * Note: Candidate core function.
+         * http://core.trac.wordpress.org/ticket/20091
+         *
+         * @since 3.4.0
+         *
+         * @param array $mods Theme modifications.
+         */
+        public function set_theme_mods( $mods ) {
+                $current = get_theme_mods();
+
+                $mods = wp_parse_args( $mods, $current );
+
+                $theme = get_stylesheet();
+                update_option( "theme_mods_$theme", $mods );
+        }
+
+        /**
+         * Start preview and customize theme.
+         * Check if customize query variable exist.
+         *
+         * @since 3.4.0
+         */
+        public function setup_theme() {
+                if ( ! isset( $_REQUEST['customize'] ) || 'on' != $_REQUEST['customize'] )
+                        return;
+
+                if ( ! $this->set_stylesheet() || isset( $_REQUEST['save'] ) )
+                        return;
+
+                $this->previewing = true;
+                do_action( 'customize_previewing' );
+        }
+
+        /**
+         * Init filters to filter theme options.
+         *
+         * @since 3.4.0
+         */
+        public function customize_previewing() {
+                global $wp_theme_directories;
+
+                show_admin_bar( false );
+
+                add_filter( 'template', array( $this, 'get_template' ) );
+                add_filter( 'stylesheet', array( $this, 'get_stylesheet' ) );
+                add_filter( 'pre_option_current_theme', array( $this, 'current_theme' ) );
+
+                // @link: http://core.trac.wordpress.org/ticket/20027
+                add_filter( 'pre_option_stylesheet', array( $this, 'get_stylesheet' ) );
+                add_filter( 'pre_option_template', array( $this, 'get_template' ) );
+
+                // Handle custom theme roots.
+                if ( count( $wp_theme_directories ) > 1 ) {
+                        add_filter( 'pre_option_stylesheet_root', array( $this, 'get_stylesheet_root' ) );
+                        add_filter( 'pre_option_template_root', array( $this, 'get_template_root' ) );
+                }
+        }
+
+        /**
+         * Register styles/scripts and Init the preview of each setting
+         *
+         * @since 3.4.0
+         */
+        public function init() {
+                do_action( 'customize_register' );
+
+                if ( ! $this->is_preview() )
+                        return;
+
+                wp_enqueue_script( 'customize-preview' );
+                add_action( 'wp_footer', array( $this, 'customize_preview_settings' ), 20 );
+
+                foreach ( $this->settings as $setting ) {
+                        $setting->preview();
+                }
+        }
+
+        /**
+         * Print javascript settings.
+         *
+         * @since 3.4.0
+         */
+        public function customize_preview_settings() {
+                $settings = array(
+                        // @todo: Perhaps grab the URL via $_POST?
+                        'parent' => esc_url( admin_url( 'themes.php' ) ),
+                );
+                ?>
+                <script type="text/javascript">
+                        (function() {
+                                if ( typeof wp === 'undefined' || ! wp.customize )
+                                        return;
+
+                                wp.customize.settings = <?php echo json_encode( $settings ); ?>;
+                        })();
+                </script>
+                <?php
+        }
+
+        /**
+         * Is it a theme preview?
+         *
+         * @since 3.4.0
+         *
+         * @return bool True if it's a preview, false if not.
+         */
+        public function is_preview() {
+                return (bool) $this->previewing;
+        }
+
+        /**
+         * Set the template name of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return bool|string Template name.
+         */
+        public function set_template() {
+                if ( ! empty( $this->template ) )
+                        return $this->template;
+
+                $template = preg_replace('|[^a-z0-9_./-]|i', '', $_REQUEST['template'] );
+                if ( validate_file( $template ) )
+                        return false;
+
+                return $this->template = $template;
+        }
+
+        /**
+         * Set the stylesheet name of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return bool|string Stylesheet name.
+         */
+        public function set_stylesheet() {
+                if ( ! empty( $this->stylesheet ) )
+                        return $this->stylesheet;
+
+                $this->set_template();
+                if ( empty( $this->template ) )
+                        return false;
+
+                if ( empty( $_REQUEST['stylesheet'] ) ) {
+                        $stylesheet = $this->template;
+                } else {
+                        $stylesheet = preg_replace( '|[^a-z0-9_./-]|i', '', $_REQUEST['stylesheet'] );
+                        if ( $stylesheet != $this->template && validate_file( $stylesheet ) )
+                                return false;
+                }
+                return $this->stylesheet = $stylesheet;
+
+        }
+
+        /**
+         * Retrieve the template name of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return string Template name.
+         */
+        public function get_template() {
+                return $this->template;
+        }
+
+        /**
+         * Retrieve the stylesheet name of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return string Stylesheet name.
+         */
+        public function get_stylesheet() {
+                return $this->stylesheet;
+        }
+
+        /**
+         * Retrieve the template root of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return string Theme root.
+         */
+        public function get_template_root() {
+                return get_raw_theme_root( $this->template, true );
+        }
+
+        /**
+         * Retrieve the stylesheet root of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return string Theme root.
+         */
+        public function get_stylesheet_root() {
+                return get_raw_theme_root( $this->stylesheet, true );
+        }
+
+        /**
+         * Filter the current theme and return the name of the previewed theme.
+         *
+         * @since 3.4.0
+         *
+         * @return string Theme name.
+         */
+        public function current_theme( $current_theme ) {
+                $themes = get_themes();
+
+                if ( ! $themes )
+                        return $current_theme;
+
+                foreach ( $themes as $theme ) {
+                        if ( $theme['Stylesheet'] == $this->stylesheet && $theme['Template'] == $this->template )
+                                return $theme['Name'];
+                }
+
+                return $current_theme;
+        }
+
+        /**
+         * Trigger save action and load customize controls.
+         *
+         * @since 3.4.0
+         */
+        public function admin_init() {
+                if ( isset( $_REQUEST['save'] ) )
+                        $this->save();
+
+                wp_enqueue_script( 'customize-loader' );
+                wp_enqueue_style( 'customize-loader' );
+
+                if ( ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
+                        return;
+
+                if ( ! isset( $_GET['customize'] ) || 'on' != $_GET['customize'] )
+                        return;
+
+                if ( ! $this->is_preview() )
+                        return;
+
+                if ( ! current_user_can( 'edit_theme_options' ) )
+                        return;
+
+                include( ABSPATH . WPINC . '/customize-controls.php' );
+
+                die;
+        }
+
+        /**
+         * Print the customize template.
+         *
+         * @since 3.4.0
+         */
+        public function admin_footer() {
+                ?>
+                <div id="customize-container">
+                        <input type="hidden" class="admin-url" value="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" />
+                        <div>
+                                <a href="#" class="return-to-admin"><?php printf( __( '&larr; Return to %s' ), get_admin_page_title() ); ?></a>
+                                <a href="#" class="collapse-sidebar button-secondary" title="<?php esc_attr_e('Collapse Sidebar'); ?>"><span></span></a>
+                        </div>
+                </div>
+                <?php
+        }
+
+        /**
+         * Switch the theme and trigger the save action of each setting.
+         *
+         * @since 3.4.0
+         */
+        public function save() {
+                if ( $this->is_preview() )
+                        return;
+
+                check_admin_referer( 'customize_controls' );
+
+                if ( ! $this->set_stylesheet() )
+                        return;
+
+                $active_template = get_template();
+                $active_stylesheet = get_stylesheet();
+
+                // Do we have to switch themes?
+                if ( $this->get_template() != $active_template || $this->get_stylesheet() != $active_stylesheet ) {
+                        if ( ! current_user_can( 'switch_themes' ) )
+                                return;
+
+                        switch_theme( $this->get_template(), $this->get_stylesheet() );
+                }
+
+                do_action( 'customize_save' );
+
+                foreach ( $this->settings as $setting ) {
+                        $setting->save();
+                }
+
+                add_action( 'admin_notices', array( $this, '_save_feedback' ) );
+        }
+
+        /**
+         * Show an admin notice after settings are saved.
+         *
+         * @since 3.4.0
+         */
+        public function _save_feedback() {
+                ?>
+                <div class="updated"><p><?php printf( __( 'Settings saved and theme activated. <a href="%s">Visit site</a>.' ), home_url( '/' ) ); ?></p></div>
+                <?php
+        }
+
+        /**
+         * Add a customize setting.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the setting. Can be a
+         * theme mod or option name.
+         * @param array $args Setting arguments.
+         */
+        public function add_setting( $id, $args = array() ) {
+                $setting = new WP_Customize_Setting( $id, $args );
+
+                $this->settings[ $setting->id ] = $setting;
+        }
+
+        /**
+         * Retrieve a customize setting.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the setting.
+         * @return object The settings object.
+         */
+        public function get_setting( $id ) {
+                if ( isset( $this->settings[ $id ] ) )
+                        return $this->settings[ $id ];
+        }
+
+        /**
+         * Remove a customize setting.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the setting.
+         */
+        public function remove_setting( $id ) {
+                unset( $this->settings[ $id ] );
+        }
+
+        /**
+         * Add a customize section.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the section.
+         * @param array $args Section arguments.
+         */
+        public function add_section( $id, $args = array() ) {
+                $section = new WP_Customize_Section( $id, $args );
+
+                $this->sections[ $section->id ] = $section;
+        }
+
+        /**
+         * Retrieve a customize section.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the section.
+         * @return object The section object.
+         */
+        public function get_section( $id ) {
+                if ( isset( $this->sections[ $id ] ) )
+                        return $this->sections[ $id ];
+        }
+
+        /**
+         * Remove a customize section.
+         *
+         * @since 3.4.0
+         *
+         * @param string $id An specific ID of the section.
+         */
+        public function remove_section( $id ) {
+                unset( $this->sections[ $id ] );
+        }
+
+        /**
+         * Helper function to compare two objects by priority.
+         *
+         * @since 3.4.0
+         *
+         * @param object $a Object A.
+         * @param object $b Object B.
+         */
+        protected function _cmp_priority( $a, $b ) {
+                $ap = $a->priority;
+                $bp = $b->priority;
+
+                if ( $ap == $bp )
+                        return 0;
+                return ( $ap > $bp ) ? 1 : -1;
+        }
+
+        /**
+         * Prepare settings and sections. Also enqueue needed scripts/styles.
+         *
+         * @since 3.4.0
+         */
+        public function prepare_controls() {
+                // Reversing makes uasort sort by time added when conflicts occur.
+
+                $this->sections = array_reverse( $this->sections );
+                uasort( $this->sections, array( $this, '_cmp_priority' ) );
+
+                $this->settings = array_reverse( $this->settings );
+                foreach ( $this->settings as $setting ) {
+                        if ( ! isset( $this->sections[ $setting->section ] ) )
+                                continue;
+
+                        $this->sections[ $setting->section ]->settings[] = $setting;
+
+                        if ( $setting->check_capabilities() )
+                                $setting->enqueue();
+                }
+
+                foreach ( $this->sections as $section ) {
+                        usort( $section->settings, array( $this, '_cmp_priority' ) );
+                }
+        }
+
+        /**
+         * Register some default controls.
+         *
+         * @since 3.4.0
+         */
+        public function register_controls() {
+
+                /* Custom Header */
+
+                $this->add_section( 'header', array(
+                        'title' => __( 'Header' ),
+                        'theme_supports' => 'custom-header',
+                ) );
+
+                $this->add_setting( 'header_textcolor', array(
+                        'label' => 'Text Color',
+                        'section' => 'header',
+                        'sanitize_callback' => 'sanitize_hexcolor',
+                        'control' => 'color',
+                        'default' => defined( 'HEADER_TEXTCOLOR' ) ? HEADER_TEXTCOLOR : ''
+                ) );
+
+                /*
+                $this->add_setting( 'display_header', array(
+                        'label' => 'Display Text',
+                        'section' => 'header',
+                        'type' => 'radio',
+                        'choices' => array(
+                                'show' => 'Yes',
+                                'hide' => 'No'
+                        ),
+                        // Showing header text is actually done by setting header_textcolor to 'blank'.
+                        // @todo: Do some JS magic to make this work (since we'll be hiding the textcolor input).
+                        'theme_mod' => false,
+                ) );
+                */
+
+                // Input type: checkbox
+                // With custom value
+                $this->add_setting( 'header_image', array(
+                        'label' => 'Random Image',
+                        'section' => 'header',
+                        'control' => 'checkbox',
+                         // @todo
+                         // not the default, it's the value.
+                         // value is saved in get_theme_support( 'custom-header' )[0][ 'random-default' ]
+                        'default' => 'random-default-image'
+                ) );
+
+                /* Custom Background */
+
+                $this->add_section( 'background', array(
+                        'title' => __( 'Background' ),
+                        'theme_supports' => 'custom-background',
+                ) );
+
+                // Input type: Color
+                // With sanitize_callback
+                $this->add_setting( 'background_color', array(
+                        'label' => 'Background Color',
+                        'section' => 'background',
+                        'control' => 'color',
+                        'default' => defined( 'BACKGROUND_COLOR' ) ? BACKGROUND_COLOR : '',
+                        'sanitize_callback' => 'sanitize_hexcolor'
+                ) );
+
+                /* Nav Menus */
+
+                $locations = get_registered_nav_menus();
+                $menus = wp_get_nav_menus();
+                $menu_locations = get_nav_menu_locations();
+                $num_locations = count( array_keys( $locations ) );
+
+                $this->add_section( 'nav', array(
+                        'title' => __( 'Navigation' ),
+                        'theme_supports' => 'menus',
+                        'description' => sprintf( _n('Your theme supports %s menu. Select which menu you would like to use.', 'Your theme supports %s menus. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ),
+                ) );
+
+                foreach ( $locations as $location => $description ) {
+                        $choices = array( 0 => '' );
+                        foreach ( $menus as $menu ) {
+                                $truncated_name = wp_html_excerpt( $menu->name, 40 );
+                                $truncated_name == $menu->name ? $menu->name : trim( $truncated_name ) . '&hellip;';
+                                $choices[ $menu->term_id ] = $truncated_name;
+                        }
+
+                        $this->add_setting( "nav_menu_locations[{$location}]", array(
+                                'label' => $description,
+                                'theme_supports' => 'menus', // Todo: Needs also widgets -- array( 'menus', 'widgets' )
+                                'section' => 'nav',
+                                'control' => 'select',
+                                'choices' => $choices,
+                                'sanitize_callback' => 'absint',
+                        ) );
+                }
+
+                /* Static Front Page */
+                // #WP19627
+
+                $this->add_section( 'static_front_page', array(
+                        'title' => __( 'Static Front Page' ),
+                //        'theme_supports' => 'static-front-page',
+                        'description' => __( 'Your theme supports a static front page.' ),
+                ) );
+
+                $choices = array();
+                $choices['posts'] = __( 'Your latest posts' );
+                $choices['page'] = __( 'A static page (select below)' );
+
+                $this->add_setting( 'show_on_front', array(
+                        'label' => __( 'Front page displays' ),
+                //        'theme_supports' => 'static-front-page',
+                        'section' => 'static_front_page',
+                        'control' => 'radio',
+                        'choices' => $choices,
+                        'default' => get_option( 'show_on_front' ),
+                        'type' => 'option',
+                        'capability' => 'manage_options'
+                ) );
+
+                $this->add_setting( 'page_on_front', array(
+                        'label' => __( 'Front page:' ),
+                //        'theme_supports' => 'static-front-page',
+                        'section' => 'static_front_page',
+                        'control' => 'dropdown-pages',
+                        'type' => 'option',
+                        'capability' => 'manage_options'
+                ) );
+
+                $this->add_setting( 'page_for_posts', array(
+                        'label' => __( 'Posts page:' ),
+                //        'theme_supports' => 'static-front-page',
+                        'section' => 'static_front_page',
+                        'control' => 'dropdown-pages',
+                        'type' => 'option',
+                        'capability' => 'manage_options'
+                ) );
+
+                /* Site Title & Tagline */
+
+                $this->add_section( 'strings', array(
+                        'title' => __( 'Site Title & Tagline' ),
+                        'description' => __( 'Customize some strings.' ),
+                ) );
+
+                $this->add_setting( 'blogname', array(
+                        'label' => __( 'Site Title' ),
+                        'section' => 'strings',
+                        'default' => get_option( 'blogname' ),
+                        'type' => 'option',
+                        'capability' => 'manage_options'
+                ) );
+
+                $this->add_setting( 'blogdescription', array(
+                        'label' => __( 'Tagline' ),
+                        'section' => 'strings',
+                        'default' => get_option( 'blogdescription' ),
+                        'type' => 'option',
+                        'capability' => 'manage_options'
+                ) );
+        }
+};
+
+// Callback function for sanitizing a hex color
+function sanitize_hexcolor( $color ) {
+        $color = preg_replace( '/[^0-9a-fA-F]/', '', $color );
+
+        if ( preg_match('|[A-Fa-f0-9]{3,6}|', $color ) )
+                return $color;
+
+        return $color;
+}
+
+// Custome render type for a dropdown menu.
+function customize_control_dropdown_pages( $setting ) {
+        printf(
+                __( '<label>%s %s</label>' ),
+                $setting->label,
+                wp_dropdown_pages(
+                        array(
+                                'name' => $setting->get_name(),
+                                'echo' => 0,
+                                'show_option_none' => __( '&mdash; Select &mdash;' ),
+                                'option_none_value' => '0',
+                                'selected' => get_option( $setting->id )
+                        )
+                )
+        );
+}
+add_action( 'customize_render_control-dropdown-pages', 'customize_control_dropdown_pages' );
</ins></span></pre></div>
<a id="trunkwpincludescsscustomizecontrolsdevcss"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/css/customize-controls.dev.css (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/css/customize-controls.dev.css         (rev 0)
+++ trunk/wp-includes/css/customize-controls.dev.css        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,216 @@
</span><ins>+body {
+        overflow: hidden;
+}
+
+.customize-section {
+        border-top: 1px solid #fff;
+        border-bottom: 1px solid #dfdfdf;
+        padding: 15px 20px;
+        margin: 0;
+}
+
+.customize-section:last-child {
+        box-shadow: 0 1px 0 0px #fff;
+}
+
+#customize-controls {
+        width: 300px;
+        height: 100%;
+        padding: 0;
+        margin: 0;
+        z-index: 10;
+        position: relative;
+        overflow: auto;
+        background: #f5f5f5;
+        box-shadow: inset -11px 0 8px -8px rgba( 0, 0, 0, 0.1 );
+        border-right: 1px solid rgba( 0, 0, 0, 0.2 );
+}
+
+#customize-controls .theme-name {
+        font-size: 16px;
+        font-weight: bold;
+        line-height: 24px;
+        display: block;
+}
+
+#customize-controls .theme-screenshot {
+        width: 258px;
+        border: 1px solid #ccc;
+}
+
+#customize-controls .submit {
+        text-align: center;
+}
+
+#customize-info {
+        padding-top: 55px;
+}
+
+#customize-theme-controls {
+        padding-bottom: 60px;
+}
+
+#customize-theme-controls ul {
+        margin: 0;
+}
+
+#customize-theme-controls ul ul {
+        margin-top: 1em;
+        display: none;
+}
+
+#customize-theme-controls ul h3 {
+        margin: 0;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        user-select: none;
+}
+
+#customize-theme-controls ul h3:hover {
+        cursor: pointer;
+}
+
+#customize-theme-controls ul h3:after {
+        content: '';
+        border-color: #ccc transparent transparent transparent;
+        border-style: solid;
+        border-width: 6px;
+        float: right;
+        margin-top: 5px;
+        margin-left: 5px;
+}
+
+ #customize-theme-controls ul h3.open:after {
+        -moz-transform: rotate(180deg);
+        -webkit-transform: rotate(180deg);
+        -o-transform: rotate(180deg);
+        -ms-transform: rotate(180deg);
+        transform: rotate(180deg);
+        -moz-transform-origin: center 3px;
+        -webkit-transform-origin: center 3px;
+        -o-transform-origin: center 3px;
+        -ms-transform-origin: center 3px;
+        transform-origin: center 3px;
+}
+
+#customize-footer {
+        border-bottom: 0;
+        border-top: 1px solid #dfdfdf;
+        position: fixed;
+        bottom: 0;
+        left: 0;
+        width: 260px;
+        padding: 15px 20px;
+        margin: 0;
+        z-index: 10;
+        background: #f5f5f5;
+        box-shadow:
+                inset -11px 0 8px -8px rgba( 0, 0, 0, 0.1 ),
+                inset 0 1px 0 0px #fff,
+                0 0 11px 0 rgba( 0, 0, 0, 0.1 );
+}
+
+#customize-preview {
+        position: fixed;
+        left: 300px;
+        right: 0;
+        top: 0;
+        bottom: 0;
+}
+
+#customize-preview iframe {
+        width: 100%;
+        height: 100%;
+}
+
+.customize-loader {
+        background: transparent;
+        border: 4px solid #666;
+        border-radius: 50%;
+        display: block;
+        margin: 10px auto;
+        text-indent: -9999px;
+
+        height: 12px;
+        width: 12px;
+
+        /* Animation */
+        -webkit-animation: customize-loader 1s infinite ease-out;
+        -moz-animation: customize-loader 1s infinite ease-out;
+        animation: customize-loader 1s infinite ease-out;
+}
+@-moz-keyframes customize-loader {
+        0% {
+                opacity: 0;
+                -moz-transform: scale(0.7);
+        }
+        40% {
+                opacity: 1;
+        }
+        100% {
+                opacity: 0;
+                -moz-transform: scale(1);
+        }
+}
+@-webkit-keyframes customize-loader {
+        0% {
+                opacity: 0;
+                -webkit-transform: scale(0.7);
+        }
+        40% {
+                opacity: 1;
+        }
+        100% {
+                opacity: 0;
+                -webkit-transform: scale(1);
+        }
+}
+@keyframes customize-loader {
+        0% {
+                opacity: 0;
+                transform: scale(0.7);
+        }
+        40% {
+                opacity: 1;
+        }
+        100% {
+                opacity: 0;
+                transform: scale(1);
+        }
+}
+
+
+/*
+ * Style for custom settings
+ */
+.customize-section select {
+        max-width: 150px;
+}
+
+.customize-section .hex-prepend {
+        float: left;
+        display: block;
+        margin: 1px -2px 0 0;
+        line-height: 15px;
+        padding: 3px 5px;
+        color: #777;
+        text-align: center;
+        background-color: #fff;
+        border: 1px solid #dfdfdf;
+        -webkit-border-radius: 3px 0 0 3px;
+        border-radius: 3px 0 0 3px;
+}
+
+.customize-section input[type="text"].hex-input {
+        -webkit-border-radius: 0 3px 3px 0;
+        border-radius: 0 3px 3px 0;
+        width: 150px;
+}
+
+.customize-section .hex-color-example {
+        border: 1px solid #dfdfdf;
+        -webkit-border-radius: 3px;
+        border-radius: 3px;
+        padding: 3px 14px;
+        background-color: #ef45da
+}
</ins></span></pre></div>
<a id="trunkwpincludescsscustomizeloaderdevcss"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/css/customize-loader.dev.css (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/css/customize-loader.dev.css         (rev 0)
+++ trunk/wp-includes/css/customize-loader.dev.css        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,90 @@
</span><ins>+body.customize-active {
+        overflow: hidden;
+}
+
+#customize-container {
+        display: none;
+        background: #fff;
+        z-index: 500000;
+        position: fixed;
+        top: 0;
+        bottom: 0;
+        left: 0;
+        right: 0;
+}
+
+.customize-active #customize-container {
+        display: block;
+}
+
+#customize-container.collapsed {
+        left: -302px;
+}
+
+#customize-container .collapse-sidebar,
+#customize-container .return-to-admin {
+        z-index: 50;
+}
+
+#customize-container div {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 260px;
+        padding: 15px 20px;
+        background: #f5f5f5;
+        box-shadow:
+                inset -11px 0 8px -8px rgba( 0, 0, 0, 0.1 ),
+                inset 0 -1px 0 #dfdfdf,
+                -1px 1px 0 #fff;
+        border-right: 1px solid rgba( 0, 0, 0, 0.2 );
+}
+
+#customize-container iframe {
+        height: 100%;
+        width: 100%;
+        z-index: 20;
+}
+
+/* Collapse Button */
+#customize-container .collapse-sidebar {
+        position: absolute;
+        top: 13px;
+        left: 265px;
+        z-index: 50;
+        display: block;
+        width: 19px;
+        height: 19px;
+        padding: 0;
+        border-radius: 50%;
+}
+#customize-container.collapsed .collapse-sidebar {
+        position: absolute;
+        left: 315px;
+}
+#customize-container .collapse-sidebar span {
+        margin-top: 2px;
+        margin-left: 2px;
+        display: block;
+        width: 15px;
+        height: 15px;
+        background: transparent url('../../wp-admin/images/arrows.png') no-repeat 0 -72px;
+}
+#customize-container.collapsed .collapse-sidebar span {
+        background-position: 0 -108px;
+}
+
+/* Animations */
+#customize-container,
+#customize-container .collapse-sidebar {
+        -moz-transition-property: left, right, top, bottom;
+        -webkit-transition-property: left, right, top, bottom;
+        -o-transition-property: left, right, top, bottom;
+        -ms-transition-property: left, right, top, bottom;
+        transition-property: left, right, top, bottom;
+        -moz-transition-duration: 0.2s;
+        -webkit-transition-duration: 0.2s;
+        -o-transition-duration: 0.2s;
+        -ms-transition-duration: 0.2s;
+        transition-duration: 0.2s;
+}
</ins></span></pre></div>
<a id="trunkwpincludescustomizecontrolsphp"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/customize-controls.php (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/customize-controls.php         (rev 0)
+++ trunk/wp-includes/customize-controls.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+<?php
+/**
+ * Customize Controls
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+
+if ( ! defined( 'ABSPATH' ) )
+        die;
+
+global $wp_scripts;
+
+$registered = $wp_scripts->registered;
+$wp_scripts = new WP_Scripts;
+$wp_scripts->registered = $registered;
+
+add_action( 'customize_controls_print_scripts', 'print_head_scripts', 20 );
+add_action( 'customize_controls_print_footer_scripts', '_wp_footer_scripts' );
+add_action( 'customize_controls_print_styles', 'print_admin_styles', 20 );
+
+do_action( 'customize_controls_init' );
+
+wp_enqueue_script( 'customize-controls' );
+wp_enqueue_style( 'customize-controls' );
+
+do_action( 'customize_controls_enqueue_scripts' );
+
+$theme = get_theme( get_current_theme() );
+
+if ( $theme['Screenshot'] )
+        $screenshot = $theme['Theme Root URI'] . '/' . $theme['Stylesheet'] . '/' . $theme['Screenshot'];
+else
+        $screenshot = '';
+
+// Let's roll.
+@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
+
+wp_user_settings();
+_wp_admin_html_begin();
+
+$admin_title = sprintf( __( '%1$s &#8212; WordPress' ), strip_tags( sprintf( __( 'Customize %s' ), $theme['Name'] ) ) );
+?><title><?php echo $admin_title; ?></title><?php
+
+do_action( 'customize_controls_print_styles' );
+do_action( 'customize_controls_print_scripts' );
+?>
+</head>
+<body>
+        <form id="customize-controls" method="post" class="wrap" target="_parent" action="<?php echo esc_url( add_query_arg( 'save', '1', admin_url( 'themes.php' ) ) ); ?>">
+                <?php wp_nonce_field( 'customize_controls' ); ?>
+                <input type="hidden" name="customize" value="on" />
+                <input type="hidden" id="customize-template" name="template" value="<?php echo esc_attr( $theme['Template'] ); ?>" />
+                <input type="hidden" id="customize-stylesheet" name="stylesheet" value="<?php echo esc_attr( $theme['Stylesheet'] ); ?>" />
+
+                <div id="customize-info" class="customize-section">
+                        <p>
+                                <strong class="theme-name"><?php echo $theme['Name']; ?></strong>
+                                <span class="theme-by"><?php printf( __( 'By %s' ), $theme['Author'] ); ?></span>
+                        </p>
+                        <?php if ( $screenshot ) : ?>
+                                <img class="theme-screenshot" src="<?php echo esc_url( $screenshot ); ?>" />
+                        <?php endif; ?>
+                </div>
+
+                <div id="customize-theme-controls"><ul>
+                        <?php
+                        foreach ( $this->sections as $section )
+                                $section->render();
+                        ?>
+                </ul></div>
+
+                <div id="customize-footer" class="customize-section">
+                        <?php
+                        submit_button( __( 'Refresh' ), 'secondary', 'refresh', false );
+                        submit_button( __( 'Save' ), 'primary', 'save', false );
+                        ?>
+                </div>
+        </form>
+        <div id="customize-preview">
+                <iframe name="customize-target"></iframe>
+        </div>
+        <?php
+
+        do_action( 'customize_controls_print_footer_scripts' );
+
+        $settings = array(
+                'preview' => esc_url( home_url( '/' ) ),
+                'values' => array(),
+                'prefix' => WP_Customize_Setting::name_prefix,
+        );
+
+        foreach ( $this->settings as $id => $setting ) {
+                $settings['values'][ $id ] = $setting->value();
+        }
+
+        ?>
+        <script type="text/javascript">
+                (function() {
+                        if ( typeof wp === 'undefined' || ! wp.customize )
+                                return;
+
+                        wp.customize.settings = <?php echo json_encode( $settings ); ?>;
+                })();
+        </script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkwpincludesjscustomizebasedevjs"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/js/customize-base.dev.js (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/js/customize-base.dev.js         (rev 0)
+++ trunk/wp-includes/js/customize-base.dev.js        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,496 @@
</span><ins>+if ( typeof wp === 'undefined' )
+        var wp = {};
+
+(function( exports, $ ){
+        var api, extend, ctor, inherits, ready,
+                slice = Array.prototype.slice;
+
+        /* =====================================================================
+         * Micro-inheritance - thank you, backbone.js.
+         * ===================================================================== */
+
+        extend = function( protoProps, classProps ) {
+                var child = inherits( this, protoProps, classProps );
+                child.extend = this.extend;
+                return child;
+        };
+
+        // Shared empty constructor function to aid in prototype-chain creation.
+        ctor = function() {};
+
+        // Helper function to correctly set up the prototype chain, for subclasses.
+        // Similar to `goog.inherits`, but uses a hash of prototype properties and
+        // class properties to be extended.
+        inherits = function( parent, protoProps, staticProps ) {
+                var child;
+
+                // The constructor function for the new subclass is either defined by you
+                // (the "constructor" property in your `extend` definition), or defaulted
+                // by us to simply call `super()`.
+                if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
+                        child = protoProps.constructor;
+                } else {
+                        child = function() {
+                                // Storing the result `super()` before returning the value
+                                // prevents a bug in Opera where, if the constructor returns
+                                // a function, Opera will reject the return value in favor of
+                                // the original object. This causes all sorts of trouble.
+                                var result = parent.apply( this, arguments );
+                                return result;
+                        };
+                }
+
+                // Inherit class (static) properties from parent.
+                $.extend( child, parent );
+
+                // Set the prototype chain to inherit from `parent`, without calling
+                // `parent`'s constructor function.
+                ctor.prototype = parent.prototype;
+                child.prototype = new ctor();
+
+                // Add prototype properties (instance properties) to the subclass,
+                // if supplied.
+                if ( protoProps )
+                        $.extend( child.prototype, protoProps );
+
+                // Add static properties to the constructor function, if supplied.
+                if ( staticProps )
+                        $.extend( child, staticProps );
+
+                // Correctly set child's `prototype.constructor`.
+                child.prototype.constructor = child;
+
+                // Set a convenience property in case the parent's prototype is needed later.
+                child.__super__ = parent.prototype;
+
+                return child;
+        };
+
+        /* =====================================================================
+         * customize function.
+         * ===================================================================== */
+        ready = $.Callbacks( 'once memory' );
+
+        /*
+         * Sugar for main customize function. Supports several signatures.
+         *
+         * customize( callback, [context] );
+         * Binds a callback to be fired when the customizer is ready.
+         * - callback, function
+         * - context, object
+         *
+         * customize( setting );
+         * Fetches a setting object by ID.
+         * - setting, string - The setting ID.
+         *
+         */
+        api = {};
+        // api = function( callback, context ) {
+        //         if ( $.isFunction( callback ) ) {
+        //                 if ( context )
+        //                         callback = $.proxy( callback, context );
+        //                 ready.add( callback );
+        //
+        //                 return api;
+        //         }
+        // }
+
+        /* =====================================================================
+         * Base class.
+         * ===================================================================== */
+
+        api.Class = function( applicator, argsArray, options ) {
+                var magic, args = arguments;
+
+                if ( applicator && argsArray && api.Class.applicator === applicator ) {
+                        args = argsArray;
+                        $.extend( this, options || {} );
+                }
+
+                magic = this;
+                if ( this.instance ) {
+                        magic = function() {
+                                return magic.instance.apply( magic, arguments );
+                        };
+
+                        $.extend( magic, this );
+                }
+
+                magic.initialize.apply( magic, args );
+                return magic;
+        };
+
+        api.Class.applicator = {};
+
+        api.Class.prototype.initialize = function() {};
+
+        /*
+         * Checks whether a given instance extended a constructor.
+         *
+         * The magic surrounding the instance parameter causes the instanceof
+         * keyword to return inaccurate results; it defaults to the function's
+         * prototype instead of the constructor chain. Hence this function.
+         */
+        api.Class.prototype.extended = function( constructor ) {
+                var proto = this;
+
+                while ( typeof proto.constructor !== 'undefined' ) {
+                        if ( proto.constructor === constructor )
+                                return true;
+                        if ( typeof proto.constructor.__super__ === 'undefined' )
+                                return false;
+                        proto = proto.constructor.__super__;
+                }
+                return false;
+        };
+
+        api.Class.extend = extend;
+
+        /* =====================================================================
+         * Light two-way binding.
+         * ===================================================================== */
+
+        api.Value = api.Class.extend({
+                initialize: function( initial, options ) {
+                        this._value = initial;
+                        this.callbacks = $.Callbacks();
+
+                        $.extend( this, options || {} );
+                },
+
+                /*
+                 * Magic. Returns a function that will become the instance.
+                 * Set to null to prevent the instance from extending a function.
+                 */
+                instance: function() {
+                        return arguments.length ? this.set.apply( this, arguments ) : this.get();
+                },
+
+                get: function() {
+                        return this._value;
+                },
+
+                set: function( to ) {
+                        var from = this._value;
+
+                        to = this.validate( to );
+
+                        // Bail if the sanitized value is null or unchanged.
+                        if ( null === to || this._value === to )
+                                return this;
+
+                        this._value = to;
+
+                        this.callbacks.fireWith( this, [ to, from ] );
+
+                        return this;
+                },
+
+                validate: function( value ) {
+                        return value;
+                },
+
+                bind: function( callback ) {
+                        this.callbacks.add.apply( this.callbacks, arguments );
+                        return this;
+                },
+
+                unbind: function( callback ) {
+                        this.callbacks.remove.apply( this.callbacks, arguments );
+                        return this;
+                },
+
+                /*
+                 * Allows the creation of composite values.
+                 * Overrides the native link method (can be reverted with `unlink`).
+                 */
+                link: function() {
+                        var keys = slice.call( arguments ),
+                                callback = keys.pop(),
+                                self = this,
+                                set, key, active;
+
+                        if ( this.links )
+                                this.unlink();
+
+                        this.links = [];
+
+                        // Single argument means a direct binding.
+                        if ( ! keys.length ) {
+                                keys = [ callback ];
+                                callback = function( value, to ) {
+                                        return to;
+                                };
+                        }
+
+                        while ( key = keys.shift() ) {
+                                if ( this._parent && $.type( key ) == 'string' )
+                                        this.links.push( this._parent[ key ] );
+                                else
+                                        this.links.push( key );
+                        }
+
+                        // Replace this.set with the assignment function.
+                        set = function() {
+                                var args, result;
+
+                                // If we call set from within the assignment function,
+                                // pass the arguments to the original set.
+                                if ( active )
+                                        return self.set.original.apply( self, arguments );
+
+                                active = true;
+
+                                args = self.links.concat( slice.call( arguments ) );
+                                result = callback.apply( self, args );
+
+                                active = false;
+
+                                if ( typeof result !== 'undefined' )
+                                        self.set.original.call( self, result );
+                        };
+
+                        set.original = this.set;
+                        this.set = set;
+
+                        // Bind the new function to the master values.
+                        $.each( this.links, function( key, value ) {
+                                value.bind( self.set );
+                        });
+
+                        this.set( this.get() );
+
+                        return this;
+                },
+
+                unlink: function() {
+                        var set = this.set;
+
+                        $.each( this.links, function( key, value ) {
+                                value.unbind( set );
+                        });
+
+                        delete this.links;
+                        this.set = this.set.original;
+                        return this;
+                }
+        });
+
+        api.ensure = function( element ) {
+                return typeof element == 'string' ? $( element ) : element;
+        };
+
+        sync = {
+                'val': {
+                        update: function() {
+                                this.element[ this._updater ]( this._value );
+                        },
+                        refresh: function() {
+                                this.set( this.element[ this._refresher ]() );
+                        }
+                }
+        }
+
+        api.Element = api.Value.extend({
+                initialize: function( element, options ) {
+                        var synchronizer = api.Element.synchronizer.html,
+                                type;
+
+                        this.element = api.ensure( element );
+                        this.events = '';
+
+                        if ( this.element.is('input, select, textarea') ) {
+                                this.events += 'change';
+                                synchronizer = api.Element.synchronizer.val;
+
+                                if ( this.element.is('input') ) {
+                                        type = this.element.prop('type');
+                                        if ( api.Element.synchronizer[ type ] )
+                                                synchronizer = api.Element.synchronizer[ type ];
+                                        if ( 'text' === type || 'password' === type )
+                                                this.events += ' keyup';
+                                }
+                        }
+
+                        api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
+                        this._value = this.get();
+
+                        this.bind( this.update );
+
+                        this.refresh = $.proxy( this.refresh, this );
+                        this.element.bind( this.events, this.refresh );
+                },
+
+                find: function( selector ) {
+                        return $( selector, this.element );
+                },
+
+                refresh: function() {},
+                update: function() {}
+        });
+
+        api.Element.synchronizer = {};
+
+        $.each( [ 'html', 'val' ], function( i, method ) {
+                api.Element.synchronizer[ method ] = {
+                        update: function( to ) {
+                                this.element[ method ]( to );
+                        },
+                        refresh: function() {
+                                this.set( this.element[ method ]() );
+                        }
+                };
+        });
+
+        api.Element.synchronizer.checkbox = {
+                update: function( to ) {
+                        this.element.prop( 'checked', to );
+                },
+                refresh: function() {
+                        this.set( this.element.prop( 'checked' ) );
+                }
+        };
+
+        api.Element.synchronizer.radio = {
+                update: function( to ) {
+                        this.element.filter( function() {
+                                return this.value === to;
+                        }).prop( 'checked', true );
+                },
+                refresh: function() {
+                        this.set( this.element.filter( ':checked' ).val() );
+                }
+        };
+
+        api.ValueFactory = function( constructor ) {
+                constructor = constructor || api.Value;
+
+                return function( key ) {
+                        var args = slice.call( arguments, 1 );
+                        this[ key ] = new constructor( api.Class.applicator, args );
+                        this[ key ]._parent = this;
+                        return this[ key ];
+                };
+        };
+
+        api.Values = api.Value.extend({
+                defaultConstructor: api.Value,
+
+                initialize: function( options ) {
+                        api.Value.prototype.initialize.call( this, {}, options || {} );
+                },
+
+                instance: function( id ) {
+                        return this.value( id );
+                },
+
+                value: function( id ) {
+                        return this._value[ id ];
+                },
+
+                has: function( id ) {
+                        return typeof this._value[ id ] !== 'undefined';
+                },
+
+                add: function( id, value ) {
+                        if ( this.has( id ) )
+                                return;
+
+                        this._value[ id ] = value;
+                        this._value[ id ]._parent = this._value;
+                        return this._value[ id ];
+                },
+
+                set: function( id ) {
+                        if ( this.has( id ) )
+                                return this.pass( 'set', arguments );
+
+                        return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
+                },
+
+                remove: function( id ) {
+                        delete this._value[ id ];
+                },
+
+                pass: function( fn, args ) {
+                        var id, value;
+
+                        args = slice.call( args );
+                        id = args.shift();
+
+                        if ( ! this.has( id ) )
+                                return;
+
+                        value = this.value( id );
+                        return value[ fn ].apply( value, args );
+                }
+        });
+
+        $.each( [ 'get', 'bind', 'unbind', 'link', 'unlink' ], function( i, method ) {
+                api.Values.prototype[ method ] = function() {
+                        return this.pass( method, arguments );
+                };
+        });
+
+        /* =====================================================================
+         * Messenger for postMessage.
+         * ===================================================================== */
+
+        api.Messenger = api.Class.extend({
+                add: api.ValueFactory(),
+
+                initialize: function( url, options ) {
+                        $.extend( this, options || {} );
+
+                        this.add( 'url', url );
+                        this.add( 'origin' ).link( 'url', function( url ) {
+                                return url().replace( /([^:]+:\/\/[^\/]+).*/, '$1' );
+                        });
+
+                        this.topics = {};
+
+                        $.receiveMessage( $.proxy( this.receive, this ), this.origin() || null );
+                },
+                receive: function( event ) {
+                        var message;
+
+                        console.log( 'messenger receiveMessage', arguments );
+
+                        // @todo: remove, this is done in the postMessage plugin.
+                        // if ( this.origin && event.origin !== this.origin )
+                        //         return;
+
+                        message = JSON.parse( event.data );
+
+                        if ( message && message.id && message.data && this.topics[ message.id ] )
+                                this.topics[ message.id ].fireWith( this, [ message.data ]);
+                },
+                send: function( id, data ) {
+                        var message;
+
+                        if ( ! this.url() )
+                                return;
+
+                        console.log( 'sending message', id, data );
+                        message = JSON.stringify({ id: id, data: data });
+                        $.postMessage( message, this.url(), this.targetWindow || null );
+                },
+                bind: function( id, callback ) {
+                        var topic = this.topics[ id ] || ( this.topics[ id ] = $.Callbacks() );
+                        topic.add( callback );
+                },
+                unbind: function( id, callback ) {
+                        if ( this.topics[ id ] )
+                                this.topics[ id ].remove( callback );
+                }
+        });
+
+        /* =====================================================================
+         * Core customize object.
+         * ===================================================================== */
+
+        api = $.extend( new api.Values(), api );
+
+        // Expose the API to the world.
+        exports.customize = api;
+})( wp, jQuery );
</ins></span></pre></div>
<a id="trunkwpincludesjscustomizecontrolsdevjs"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/js/customize-controls.dev.js (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/js/customize-controls.dev.js         (rev 0)
+++ trunk/wp-includes/js/customize-controls.dev.js        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,101 @@
</span><ins>+(function( exports, $ ){
+        var api = wp.customize;
+
+        api.Previewer = api.Messenger.extend({
+                /**
+                 * Requires params:
+                 * - iframe - a selector or jQuery element
+                 * - form - a selector or jQuery element
+                 * - url - the URL of preview frame
+                 */
+                initialize: function( params, options ) {
+                        $.extend( this, options || {} );
+
+                        this.iframe = api.ensure( params.iframe );
+                        this.form = api.ensure( params.form );
+
+                        api.Messenger.prototype.initialize.call( this, params.url, {
+                                targetWindow: this.iframe[0].contentWindow
+                        });
+
+                        this._formOriginalProps = {
+                                target: this.form.prop('target'),
+                                action: this.form.prop('action')
+                        };
+
+                        this.bind( 'url', function( url ) {
+                                // Bail if we're navigating to the current url, to a different origin, or wp-admin.
+                                if ( this.url() == url || 0 !== url.indexOf( this.origin() + '/' ) || -1 !== url.indexOf( 'wp-admin' ) )
+                                        return;
+
+                                this.url( url );
+                                this.refresh();
+                        });
+
+                        this.refresh();
+                },
+                refresh: function() {
+                        this.submit({
+                                target: this.iframe.prop('name'),
+                                action: this.url()
+                        });
+                },
+                submit: function( props ) {
+                        if ( props )
+                                this.form.prop( props );
+                        this.form.submit();
+                        if ( props )
+                                this.form.prop( this._formOriginalProps );
+                }
+        });
+
+        /* =====================================================================
+         * Ready.
+         * ===================================================================== */
+
+        $( function() {
+                var previewer,
+                        controls = $('[name^="' + api.settings.prefix + '"]');
+
+                // Initialize Previewer
+                previewer = new api.Previewer({
+                        iframe: '#customize-preview iframe',
+                        form: '#customize-controls',
+                        url: api.settings.preview
+                });
+
+                $.each( api.settings.values, function( id, value ) {
+                        var elements = controls.filter( '[name="' + api.settings.prefix + id + '"]' ),
+                                setting = api.set( id, value );
+
+                        setting.control = new wp.customize.Element( elements );
+
+                        setting.control.link( setting );
+                        setting.link( setting.control );
+                });
+
+                // Temporary accordion code.
+                $('.control-section h3').click( function() {
+                        $( this ).siblings('ul').slideToggle( 200 );
+                        $( this ).toggleClass( 'open' );
+                        return false;
+                });
+
+                // Button bindings.
+                $('#save').click( function() {
+                        previewer.submit();
+                        return false;
+                });
+
+                $('#refresh').click( function() {
+                        previewer.refresh();
+                        return false;
+                });
+
+                // Fetch prefixed settings.
+                $('[name^="' + api.settings.prefix + '"]').each( function() {
+                        // console.log( this.name );
+                });
+        });
+
+})( wp, jQuery );
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkwpincludesjscustomizeloaderdevjs"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/js/customize-loader.dev.js (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/js/customize-loader.dev.js         (rev 0)
+++ trunk/wp-includes/js/customize-loader.dev.js        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+if ( typeof wp === 'undefined' )
+        var wp = {};
+
+(function( exports, $ ){
+        var Loader = {
+                initialize: function() {
+                        this.body = $( document.body );
+                        this.element = $( '#customize-container' );
+                        this.base = $( '.admin-url', this.element ).val();
+                        this.doc_title = $( document ).attr( 'title' );
+
+                        this.element.on( 'click', '.return-to-admin', function() {
+                                Loader.close();
+                                return false;
+                        });
+
+                        this.element.on( 'click', '.collapse-sidebar', function() {
+                                Loader.element.toggleClass('collapsed');
+                                return false;
+                        });
+                },
+                open: function( params ) {
+                        params.customize = 'on';
+
+                        this.element.append( '<iframe />' );
+                        this.iframe = $( 'iframe' ).attr( 'src', this.base + '?' + jQuery.param( params ) );
+
+                        $('iframe').load( function() {
+                                title = $(this).contents().find( 'title' ).text();
+                                $( document ).attr( 'title', title );
+                        });
+
+                        this.element.fadeIn( 200, function() {
+                                Loader.body.addClass( 'customize-active' );
+                        });
+                },
+                close: function() {
+                        this.element.fadeOut( 200, function() {
+                                Loader.iframe.remove();
+                                Loader.iframe = null;
+                                Loader.body.removeClass( 'customize-active' );
+                                $( document ).attr( 'title', Loader.doc_title );
+                        });
+                }
+        };
+
+        $( function() {
+                Loader.initialize();
+
+                // Override 'preview' links on themes page.
+                $('.thickbox-preview').click( function( event ) {
+                        var href, template, stylesheet;
+
+                        // Stop the thickbox.
+                        event.preventDefault();
+                        event.stopImmediatePropagation();
+
+                        // Extract the template/stylesheet from the preview link's url.
+                        href = $(this).attr('href');
+                        template = href.match('template=([^&]*)')[1];
+                        stylesheet = href.match('stylesheet=([^&]*)')[1];
+
+                        // Load the theme.
+                        Loader.open({
+                                template: template,
+                                stylesheet: stylesheet
+                        });
+                }).filter( function() {
+                        return 'Preview' == $(this).text();
+                }).text('Customize');
+        });
+
+        // Expose the API to the world.
+        exports.CustomizeLoader = Loader;
+})( wp, jQuery );
</ins></span></pre></div>
<a id="trunkwpincludesjscustomizepreviewdevjs"></a>
<div class="addfile"><h4>Added: trunk/wp-includes/js/customize-preview.dev.js (0 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/js/customize-preview.dev.js         (rev 0)
+++ trunk/wp-includes/js/customize-preview.dev.js        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+(function( exports, $ ){
+        var api = wp.customize;
+
+        api.Preview = api.Messenger.extend({
+                /**
+                 * Requires params:
+                 * - url - the URL of preview frame
+                 *
+                 * @todo: Perhaps add a window.onbeforeunload dialog in case the theme
+                 * somehow attempts to leave the page and we don't catch it
+                 * (which really shouldn't happen).
+                 */
+                initialize: function( url, options ) {
+                        var self = this;
+
+                        $.extend( this, options || {} );
+
+                        api.Messenger.prototype.initialize.call( this, url );
+
+                        this.body = $( document.body );
+                        this.body.on( 'click.preview', 'a', function( event ) {
+                                event.preventDefault();
+                                self.send( 'url', $(this).attr('href') );
+                        });
+
+                        // You cannot submit forms.
+                        // @todo: Namespace customizer settings so that we can mix the
+                        // $_POST data with the customize setting $_POST data.
+                        this.body.on( 'submit.preview', 'form', function( event ) {
+                                event.preventDefault();
+                        });
+
+                        this.bind( 'url', function( url ) {
+                                this.url( url );
+                                this.refresh();
+                        });
+                },
+                refresh: function() {
+                        this.submit({
+                                target: this.iframe.prop('name'),
+                                action: this.url()
+                        });
+                },
+                submit: function( props ) {
+                        if ( props )
+                                this.form.prop( props );
+                        this.form.submit();
+                        if ( props )
+                                this.form.prop( this._formOriginalProps );
+                }
+        });
+
+        $( function() {
+                var preview;
+
+                preview = new api.Preview( api.settings.parent );
+        });
+
+})( wp, jQuery );
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkwpincludesscriptloaderphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/script-loader.php (19994 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/script-loader.php        2012-02-25 02:15:56 UTC (rev 19994)
+++ trunk/wp-includes/script-loader.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -289,6 +289,11 @@
</span><span class="cx">
</span><span class="cx">         $scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array('jquery'), 'r6', 1 );
</span><span class="cx">
</span><ins>+        $scripts->add( 'customize-loader', "/wp-includes/js/customize-loader$suffix.js", array( 'jquery' ), false, 1 );
+        $scripts->add( 'customize-base', "/wp-includes/js/customize-base$suffix.js", array( 'jquery-postmessage', 'json2' ), false, 1 );
+        $scripts->add( 'customize-controls', "/wp-includes/js/customize-controls$suffix.js", array( 'customize-base' ), false, 1 );
+        $scripts->add( 'customize-preview', "/wp-includes/js/customize-preview$suffix.js", array( 'customize-base' ), false, 1 );
+
</ins><span class="cx">         if ( is_admin() ) {
</span><span class="cx">                 $scripts->add( 'ajaxcat', "/wp-admin/js/cat$suffix.js", array( 'wp-lists' ) );
</span><span class="cx">                 $scripts->add_data( 'ajaxcat', 'group', 1 );
</span><span class="lines">@@ -464,6 +469,8 @@
</span><span class="cx">         $styles->add( 'wp-jquery-ui-dialog', "/wp-includes/css/jquery-ui-dialog$suffix.css" );
</span><span class="cx">         $styles->add( 'editor-buttons', "/wp-includes/css/editor-buttons$suffix.css" );
</span><span class="cx">         $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css" );
</span><ins>+        $styles->add( 'customize-loader', "/wp-includes/css/customize-loader$suffix.css" );
+        $styles->add( 'customize-controls', "/wp-includes/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie' ) );
</ins><span class="cx">
</span><span class="cx">         foreach ( $rtl_styles as $rtl_style ) {
</span><span class="cx">                 $styles->add_data( $rtl_style, 'rtl', true );
</span></span></pre></div>
<a id="trunkwpincludesthemephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/theme.php (19994 => 19995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/theme.php        2012-02-25 02:15:56 UTC (rev 19994)
+++ trunk/wp-includes/theme.php        2012-02-25 04:12:43 UTC (rev 19995)
</span><span class="lines">@@ -2082,3 +2082,15 @@
</span><span class="cx">                 update_option( 'theme_switched', false );
</span><span class="cx">         }
</span><span class="cx"> }
</span><ins>+
+function wp_customize_load() {
+        // Load on themes.php or ?customize=on
+        if ( ! ( isset( $_REQUEST['customize'] ) && 'on' == $_REQUEST['customize'] ) && 'themes.php' != $GLOBALS['pagenow'] )
+                return;
+
+        require( ABSPATH . WPINC . '/class-wp-customize.php' );
+        // Init Customize class
+        // @todo Dependency injection instead
+        $GLOBALS['customize'] = new WP_Customize;
+}
+add_action( 'plugins_loaded', 'wp_customize_load' );
</ins></span></pre>
</div>
</div>
</body>
</html>