commit 6f2b105ca09c630b184ffb818e1ec355e7708940 Author: root Date: Fri Aug 30 19:30:19 2019 +0200 fork diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..923029d --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.svn +# .project +Thumbs.db +.DS_Store* +# .settings +# .buildpath +*.pyc +.idea/ +/log.txt +*.sublime-workspace +.c9 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bfaf069 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "js/jquery-colorpicker"] + path = js/jquery-colorpicker +url=git://github.com/aramk/colorpicker.git +[submodule "langs/ada"] + path = langs/ada + url = https://github.com/antiphasis/crayon-lang-ada.git +[submodule "langs/vbnet"] + path = langs/vbnet +url=https://github.com/NuGardt/crayon-lang-vbnet.git diff --git a/crayon-syntax-highlighter.sublime-project b/crayon-syntax-highlighter.sublime-project new file mode 100644 index 0000000..c3e83ab --- /dev/null +++ b/crayon-syntax-highlighter.sublime-project @@ -0,0 +1,13 @@ +{ + "folders": + [ + { + "follow_symlinks": true, + "path": ".", + "folder_exclude_patterns": [ + "min", + "trans" + ] + } + ] +} diff --git a/crayon_fonts.class.php b/crayon_fonts.class.php new file mode 100644 index 0000000..4995d95 --- /dev/null +++ b/crayon_fonts.class.php @@ -0,0 +1,36 @@ +set_default(self::DEFAULT_FONT, self::DEFAULT_FONT_NAME); + $this->directory(CRAYON_FONT_PATH); + $this->relative_directory(CRAYON_FONT_DIR); + $this->extension('css'); + + CrayonLog::debug("Setting font directories"); + $upload = CrayonGlobalSettings::upload_path(); + if ($upload) { + $this->user_directory($upload . CRAYON_FONT_DIR); + if (!is_dir($this->user_directory())) { + CrayonGlobalSettings::mkdir($this->user_directory()); + CrayonLog::debug($this->user_directory(), "FONT USER DIR"); + } + } else { + CrayonLog::syslog("Upload directory is empty: " . $upload . " cannot load fonts."); + } + CrayonLog::debug($this->directory()); + CrayonLog::debug($this->user_directory()); + } + +} +?> \ No newline at end of file diff --git a/crayon_formatter.class.php b/crayon_formatter.class.php new file mode 100644 index 0000000..2cdff2c --- /dev/null +++ b/crayon_formatter.class.php @@ -0,0 +1,633 @@ +is_highlighted()) { + $code = self::clean_code($code, FALSE, FALSE, FALSE, TRUE); + /* Perform the replace on the code using the regex, pass the captured matches for + formatting before they are replaced */ + try { + CrayonParser::parse($language->id()); + // Match language regex + $elements = $language->elements(); + $regex = $language->regex(); + if (!empty($regex) && !empty($elements)) { + // Get array of CrayonElements + self::$elements = array_values($elements); + $code = preg_replace_callback($regex, 'CrayonFormatter::format_match', $code); + } + } catch (Exception $e) { + $error = 'An error occured when formatting: ' . $e->message(); + $hl ? $hl->log($error) : CrayonLog::syslog($error); + } + return $code; + } else { + return self::clean_code($code, TRUE, TRUE, TRUE, TRUE); + } + } + + /* Performs a replace to format each match based on the captured element. */ + private static function format_match($matches) { + /* First index in $matches is full match, subsequent indices are groups. + * Minimum number of elements in array is 2, so minimum captured group is 0. */ + $captured_group_number = count($matches) - 2; + $code = $matches[0]; + if (array_key_exists($captured_group_number, self::$elements)) { + $captured_element = self::$elements[$captured_group_number]; + // Avoid capturing and formatting internal Crayon elements + if ($captured_element->name() == CrayonParser::CRAYON_ELEMENT) { + return $code; // Return as is + } else { + // Separate lines and add css class, keep extended class last to allow overriding + $fallback_css = CrayonLangs::known_elements($captured_element->fallback()); + $element_css = $captured_element->css(); + $css = !empty($fallback_css) ? $fallback_css . ' ' . $element_css : $element_css; + return self::split_lines($code, $css); + } + } else { + // All else fails, return the match + return $matches[0]; + } + } + + /* Prints the formatted code, option to override the line numbers with a custom string */ + public static function print_code($hl, $code, $line_numbers = TRUE, $print = TRUE) { + global $CRAYON_VERSION; + + // We can print either block or inline, inline is treated differently, factor out common stuff here + $output = ''; + // Used for style tag + $main_style = $code_style = $toolbar_style = $info_style = $font_style = $line_style = $pre_style = ''; + // Unique ID for this instance of Crayon + $uid = 'crayon-' . $hl->id(); + // Print theme id + // We make the assumption that the id is correct (checked in crayon_wp) + $theme_id = $hl->setting_val(CrayonSettings::THEME); + $theme_id_dashed = CrayonUtil::space_to_hyphen($theme_id); + if (!$hl->setting_val(CrayonSettings::ENQUEUE_THEMES)) { + $output .= CrayonResources::themes()->get_css($theme_id); + } + + // Print font id + // We make the assumption that the id is correct (checked in crayon_wp) + $font_id = $hl->setting_val(CrayonSettings::FONT); + $font_id_dashed = CrayonUtil::space_to_hyphen($font_id); + if (!$hl->setting_val(CrayonSettings::ENQUEUE_FONTS)) { + $output .= CrayonResources::fonts()->get_css($font_id); + } + + // Inline margin + if ($hl->is_inline()) { + $inline_margin = $hl->setting_val(CrayonSettings::INLINE_MARGIN) . 'px !important;'; + } + + // Determine font size + // TODO improve logic + if ($hl->setting_val(CrayonSettings::FONT_SIZE_ENABLE)) { + $_font_size = $hl->setting_val(CrayonSettings::FONT_SIZE); + $_font_size = $_font_size . 'px !important;'; + $_line_height = $hl->setting_val(CrayonSettings::LINE_HEIGHT); + // Don't allow line height to be less than font size + $line_height = ($_line_height > $_font_size ? $_line_height : $_font_size) . 'px !important;'; + $toolbar_height = $_font_size * 1.5 . 'px !important;'; + $info_height = $_font_size * 1.4 . 'px !important;'; + + $font_style .= "font-size: $_font_size line-height: $line_height"; + $toolbar_style .= "font-size: $_font_size"; + $line_style .= "height: $line_height"; + + if ($hl->is_inline()) { + $font_style .= "font-size: $_font_size"; + } else { + $toolbar_style .= "height: $toolbar_height line-height: $toolbar_height"; + $info_style .= "min-height: $info_height line-height: $info_height"; + } + } else if (!$hl->is_inline()) { + if (($_font_size = CrayonGlobalSettings::get(CrayonSettings::FONT_SIZE)) !== FALSE) { + $_font_size = $_font_size->def() . 'px !important;'; + $line_height = ($_font_size * 1.4) . 'px !important;'; + } + } + + $tab = $hl->setting_val(CrayonSettings::TAB_SIZE); + $pre_style = "-moz-tab-size:$tab; -o-tab-size:$tab; -webkit-tab-size:$tab; tab-size:$tab;"; + + // This will return from function with inline print + if ($hl->is_inline()) { + $wrap = !$hl->setting_val(CrayonSettings::INLINE_WRAP) ? 'crayon-syntax-inline-nowrap' : ''; + $output .= ' + ' . + '' . $code . '' . + ''; + return $output; + } + + // Below code only for block (default) printing + + // Generate the code lines and separate each line as a div + $print_code = ''; + $print_nums = ''; + $hl->line_count(preg_match_all("#(?:^|(?<=\r\n|\n))[^\r\n]*#", $code, $code_lines)); + + // The line number to start from + $start_line = $hl->setting_val(CrayonSettings::START_LINE); + $marking = $hl->setting_val(CrayonSettings::MARKING); + $striped = $hl->setting_val(CrayonSettings::STRIPED); + $range = $hl->setting_val(CrayonSettings::RANGES) ? $hl->range() : FALSE; + for ($i = 1; $i <= $hl->line_count(); $i++) { + // Check if the current line is in the range of code to display + if ($range) { + if ($i < $range[0]) { + continue; + } else if ($i > $range[1]) { + break; + } + } + $code_line = $code_lines[0][$i - 1]; + + // If line is blank, add a space so the div has the correct height + if ($code_line == '') { + $code_line = ' '; + } + + // Check if the current line has been selected + $marked_lines = $hl->marked(); + // Check if lines need to be marked as important + if ($marking && in_array($i, $marked_lines)) { + $marked_num = ' crayon-marked-num'; + $marked_line = ' crayon-marked-line'; + // If multiple lines are marked, only show borders for top and bottom lines + if (!in_array($i - 1, $marked_lines)) { + $marked_num .= ' crayon-top'; + $marked_line .= ' crayon-top'; + } + // Single lines are both the top and bottom of the multiple marked lines + if (!in_array($i + 1, $marked_lines)) { + $marked_num .= ' crayon-bottom'; + $marked_line .= ' crayon-bottom'; + } + } else { + $marked_num = $marked_line = ''; + } + // Stripe odd lines + if ($striped && $i % 2 == 0) { + $striped_num = ' crayon-striped-num'; + $striped_line = ' crayon-striped-line'; + } else { + $striped_num = $striped_line = ''; + } + // Generate the lines + $line_num = $start_line + $i - 1; + $line_id = $uid . '-' . $line_num; + $print_code .= '
' . $code_line . '
'; + if (!is_string($line_numbers)) { + $print_nums .= '
' . $line_num . '
'; + } + } + // If $line_numbers is a string, display it + if (is_string($line_numbers) && !empty($line_numbers)) { + $print_nums .= '
' . $line_numbers . '
'; + } else if (empty($line_numbers)) { + $print_nums = FALSE; + } + // Determine whether to print title, encode characters + $title = $hl->title(); + // Decode if needed + if ($hl->setting_val(CrayonSettings::DECODE_ATTRIBUTES)) { + $title = CrayonUtil::html_entity_decode($title); + } + $print_title = '' . $title . ''; + // Determine whether to print language + $print_lang = ''; + // XXX Use for printing the regex + if ($hl->language()) { + $lang = $hl->language()->name(); + switch ($hl->setting_index(CrayonSettings::SHOW_LANG)) { + case 0 : + if ($hl->language()->id() == CrayonLangs::DEFAULT_LANG) { + break; + } + // Falls through + case 1 : + $print_lang = '' . $lang . ''; + break; + } + } + // Disable functionality for errors + $error = $hl->error(); + // Combined settings for code + $code_settings = ''; + // Disable mouseover for touchscreen devices and mobiles, if we are told to + $touch = FALSE; // Whether we have detected a touchscreen device + if ($hl->setting_val(CrayonSettings::TOUCHSCREEN) && CrayonUtil::is_touch()) { + $touch = TRUE; + $code_settings .= ' touchscreen'; + } + + // Disabling Popup + if (!$hl->setting_val(CrayonSettings::POPUP)) { + $code_settings .= ' no-popup'; + } + + // Minimize + if (!$hl->setting_val(CrayonSettings::MINIMIZE)) { + $code_settings .= ' minimize'; + } + + // Draw the plain code and toolbar + $toolbar_settings = $print_plain_button = $print_copy_button = ''; + $toolbar_index = $hl->setting_index(CrayonSettings::TOOLBAR); + if (empty($error) && ($toolbar_index != 2 || $hl->setting_val(CrayonSettings::MINIMIZE))) { + // Enable mouseover setting for toolbar + if ($toolbar_index == 0 && !$touch) { + // No touchscreen detected + $toolbar_settings .= ' mouseover'; + if ($hl->setting_val(CrayonSettings::TOOLBAR_OVERLAY)) { + $toolbar_settings .= ' overlay'; + } + if ($hl->setting_val(CrayonSettings::TOOLBAR_HIDE)) { + $toolbar_settings .= ' hide'; + } + if ($hl->setting_val(CrayonSettings::TOOLBAR_DELAY)) { + $toolbar_settings .= ' delay'; + } + } else if ($toolbar_index == 1) { + // Always display the toolbar + $toolbar_settings .= ' show'; + } else if ($toolbar_index == 2) { + $toolbar_settings .= ' never-show'; + } + + $buttons = array(); + + if ($hl->setting_val(CrayonSettings::NUMS_TOGGLE)) { + $buttons['nums'] = crayon__('Toggle Line Numbers'); + } + + if ($hl->setting_val(CrayonSettings::PLAIN) && $hl->setting_val(CrayonSettings::PLAIN_TOGGLE)) { + $buttons['plain'] = crayon__('Toggle Plain Code'); + } + + if ($hl->setting_val(CrayonSettings::WRAP_TOGGLE)) { + $buttons['wrap'] = crayon__('Toggle Line Wrap'); + } + + if ($hl->setting_val(CrayonSettings::EXPAND_TOGGLE)) { + $buttons['expand'] = crayon__('Expand Code'); + } + + if (!$touch && $hl->setting_val(CrayonSettings::PLAIN) && $hl->setting_val(CrayonSettings::COPY)) { + $buttons['copy'] = crayon__('Copy'); + } + + if ($hl->setting_val(CrayonSettings::POPUP)) { + $buttons['popup'] = crayon__('Open Code In New Window'); + } + + $buttons_str = ''; + foreach ($buttons as $button => $value) { + $buttons_str .= '
$value); + } + foreach ($value as $k => $v) { + $buttons_str .= ' ' . $k . '="' . $v . '"'; + } + $buttons_str .= '>
'; + } + + /* The table is rendered invisible by CSS and enabled with JS when asked to. If JS + is not enabled or fails, the toolbar won't work so there is no point to display it. */ + $print_plus = $hl->is_mixed() && $hl->setting_val(CrayonSettings::SHOW_MIXED) ? '' : ''; + $buttons = $print_plus . $buttons_str . $print_lang; + $toolbar = ' +
' . $print_title . ' +
' . $buttons . '
+
'; + + } else { + $toolbar = $buttons = $plain_settings = ''; + } + + if (empty($error) && $hl->setting_val(CrayonSettings::PLAIN)) { + // Different events to display plain code + switch ($hl->setting_index(CrayonSettings::SHOW_PLAIN)) { + case 0 : + $plain_settings = 'dblclick'; + break; + case 1 : + $plain_settings = 'click'; + break; + case 2 : + $plain_settings = 'mouseover'; + break; + default : + $plain_settings = ''; + } + if ($hl->setting_val(CrayonSettings::SHOW_PLAIN_DEFAULT)) { + $plain_settings .= ' show-plain-default'; + } + $readonly = $touch ? '' : 'readonly'; + $print_plain = $print_plain_button = ''; + $textwrap = !$hl->setting_val(CrayonSettings::WRAP) ? 'wrap="soft"' : ''; + $print_plain = ''; + } else { + $print_plain = $plain_settings = $plain_settings = ''; + } + + // Line numbers visibility + $num_vis = $num_settings = ''; + if ($line_numbers === FALSE) { + $num_vis = 'crayon-invisible'; + } else { + $num_settings = ($hl->setting_val(CrayonSettings::NUMS) ? 'show' : 'hide'); + } + + // Determine scrollbar visibility + $code_settings .= $hl->setting_val(CrayonSettings::SCROLL) && !$touch ? ' scroll-always' : ' scroll-mouseover'; + + // Disable animations + if ($hl->setting_val(CrayonSettings::DISABLE_ANIM)) { + $code_settings .= ' disable-anim'; + } + + // Wrap + if ($hl->setting_val(CrayonSettings::WRAP)) { + $code_settings .= ' wrap'; + } + + // Expand + if ($hl->setting_val(CrayonSettings::EXPAND)) { + $code_settings .= ' expand'; + } + + // Determine dimensions + if ($hl->setting_val(CrayonSettings::HEIGHT_SET)) { + $height_style = self::dimension_style($hl, CrayonSettings::HEIGHT); + // XXX Only set height for main, not code (if toolbar always visible, code will cover main) + if ($hl->setting_index(CrayonSettings::HEIGHT_UNIT) == 0) { + $main_style .= $height_style; + } + } + if ($hl->setting_val(CrayonSettings::WIDTH_SET)) { + $width_style = self::dimension_style($hl, CrayonSettings::WIDTH); + $code_style .= $width_style; + if ($hl->setting_index(CrayonSettings::WIDTH_UNIT) == 0) { + $main_style .= $width_style; + } + } + + // Determine margins + if ($hl->setting_val(CrayonSettings::TOP_SET)) { + $code_style .= ' margin-top: ' . $hl->setting_val(CrayonSettings::TOP_MARGIN) . 'px;'; + } + if ($hl->setting_val(CrayonSettings::BOTTOM_SET)) { + $code_style .= ' margin-bottom: ' . $hl->setting_val(CrayonSettings::BOTTOM_MARGIN) . 'px;'; + } + if ($hl->setting_val(CrayonSettings::LEFT_SET)) { + $code_style .= ' margin-left: ' . $hl->setting_val(CrayonSettings::LEFT_MARGIN) . 'px;'; + } + if ($hl->setting_val(CrayonSettings::RIGHT_SET)) { + $code_style .= ' margin-right: ' . $hl->setting_val(CrayonSettings::RIGHT_MARGIN) . 'px;'; + } + + // Determine horizontal alignment + $align_style = ''; + switch ($hl->setting_index(CrayonSettings::H_ALIGN)) { + case 1 : + $align_style = ' float: left;'; + break; + case 2 : + $align_style = ' float: none; margin-left: auto; margin-right: auto;'; + break; + case 3 : + $align_style = ' float: right;'; + break; + } + $code_style .= $align_style; + + // Determine allowed float elements + if ($hl->setting_val(CrayonSettings::FLOAT_ENABLE)) { + $clear_style = ' clear: none;'; + } else { + $clear_style = ''; + } + $code_style .= $clear_style; + + // Determine if operating system is mac + $crayon_os = CrayonUtil::is_mac() ? 'mac' : 'pc'; + + // Produce output + $output .= ' + '; + // Debugging stats + $runtime = $hl->runtime(); + if (!$hl->setting_val(CrayonSettings::DISABLE_RUNTIME) && is_array($runtime) && !empty($runtime)) { + $output = '' + . CRAYON_NL . $output . CRAYON_NL . '' . CRAYON_NL; + } + // Determine whether to print to screen or save + if ($print) { + echo $output; + } else { + return $output; + } + } + + public static function print_error($hl, $error, $line_numbers = 'ERROR', $print = TRUE) { + if (get_class($hl) != CRAYON_HIGHLIGHTER) { + return; + } + // Either print the error returned by the handler, or a custom error message + if ($hl->setting_val(CrayonSettings::ERROR_MSG_SHOW)) { + $error = $hl->setting_val(CrayonSettings::ERROR_MSG); + } + $error = self::split_lines(trim($error), 'crayon-error'); + return self::print_code($hl, $error, $line_numbers, $print); + } + + // Delimiters ============================================================= + + public static function format_mixed_code($code, $language, $hl) { + self::$curr = $hl; + self::$delim_pieces = array(); + // Remove crayon internal element from INPUT code + $code = preg_replace('#' . CrayonParser::CRAYON_ELEMENT_REGEX_CAPTURE . '#msi', '', $code); + + if (self::$delimiters == NULL) { + self::$delimiters = CrayonResources::langs()->delimiters(); + } + + // Find all delimiters in all languages + if (self::$delim_regex == NULL) { + self::$delim_regex = '#(' . implode(')|(', array_values(self::$delimiters)) . ')#msi'; + } + + // Extract delimited code, replace with internal elements + $internal_code = preg_replace_callback(self::$delim_regex, 'CrayonFormatter::delim_to_internal', $code); + + // Format with given language + $formatted_code = CrayonFormatter::format_code($internal_code, $language, $hl); + + // Replace internal elements with delimited pieces + $formatted_code = preg_replace_callback('#\{\{crayon-internal:(\d+)\}\}#', 'CrayonFormatter::internal_to_code', $formatted_code); + + return $formatted_code; + } + + public static function delim_to_internal($matches) { + // Mark as mixed so we can show (+) + self::$curr->is_mixed(TRUE); + $capture_group = count($matches) - 2; + $capture_groups = array_keys(self::$delimiters); + $lang_id = $capture_groups[$capture_group]; + if (($lang = CrayonResources::langs()->get($lang_id)) === NULL) { + return $matches[0]; + } + $internal = sprintf('{{crayon-internal:%d}}', count(self::$delim_pieces)); + // TODO fix + self::$delim_pieces[] = CrayonFormatter::format_code($matches[0], $lang, self::$curr); + return $internal; + } + + public static function internal_to_code($matches) { + return self::$delim_pieces[intval($matches[1])]; + } + + // Auxiliary Methods ====================================================== + /* Prepares code for formatting. */ + public static function clean_code($code, $escape = TRUE, $spaces = FALSE, $tabs = FALSE, $lines = FALSE) { + if (empty($code)) { + return $code; + } + /* Convert <, > and & characters to entities, as these can appear as HTML tags and entities. */ + if ($escape) { + $code = CrayonUtil::htmlspecialchars($code); + } + if ($spaces) { + // Replace 2 spaces with html escaped characters + $code = preg_replace('#[ ]{2}#msi', '  ', $code); + } + if ($tabs && CrayonGlobalSettings::val(CrayonSettings::TAB_CONVERT)) { + // Replace tabs with 4 spaces + $code = preg_replace('#\t#', str_repeat(' ', CrayonGlobalSettings::val(CrayonSettings::TAB_SIZE)), $code); + } + if ($lines) { + $code = preg_replace('#(\r\n)|\r|\n#msi', "\r\n", $code); + } + return $code; + } + + /* Converts the code to entities and wraps in a
*/ + public static function plain_code($code, $encoded = TRUE) { + if (is_array($code)) { + // When used as a preg_replace_callback + $code = $code[1]; + } + if (!$encoded) { + $code = CrayonUtil::htmlentities($code); + } + if (CrayonGlobalSettings::val(CrayonSettings::TRIM_WHITESPACE)) { + $code = trim($code); + } + return '
' . $code . '
'; + } + + public static function split_lines($code, $class) { + $code = self::clean_code($code, TRUE, TRUE, TRUE, FALSE); + $class = preg_replace('#(\w+)#m', 'crayon-$1', $class); + $code = preg_replace('#^([^\r\n]+)(?=\r\n|\r|\n|$)#m', '$1', $code); + return $code; + } + + private static function dimension_style($hl, $name) { + $mode = $unit = ''; + switch ($name) { + case CrayonSettings::HEIGHT : + $mode = CrayonSettings::HEIGHT_MODE; + $unit = CrayonSettings::HEIGHT_UNIT; + break; + case CrayonSettings::WIDTH : + $mode = CrayonSettings::WIDTH_MODE; + $unit = CrayonSettings::WIDTH_UNIT; + break; + } + // XXX Uses actual index value to identify options + $mode = $hl->setting_index($mode); + $unit = $hl->setting_index($unit); + $dim_mode = $dim_unit = ''; + if ($mode !== FALSE) { + switch ($mode) { + case 0 : + $dim_mode .= 'max-'; + break; + case 1 : + $dim_mode .= 'min-'; + break; + } + } + $dim_mode .= $name; + if ($unit !== FALSE) { + switch ($unit) { + case 0 : + $dim_unit = 'px'; + break; + case 1 : + $dim_unit = '%'; + break; + } + } + return ' ' . $dim_mode . ': ' . $hl->setting_val($name) . $dim_unit . ';'; + } +} + +?> diff --git a/crayon_highlighter.class.php b/crayon_highlighter.class.php new file mode 100644 index 0000000..72b86e6 --- /dev/null +++ b/crayon_highlighter.class.php @@ -0,0 +1,423 @@ +url($url); + } + + if ($language !== NULL) { + $this->language($language); + } + // Default ID + $id = $id !== NULL ? $id : uniqid(); + $this->id($id); + } + + /* Tries to load the code locally, then attempts to load it remotely */ + private function load() { + if (empty($this->url)) { + $this->error('The specified URL is empty, please provide a valid URL.'); + return; + } + // Try to replace the URL with an absolute path if it is local, used to prevent scripts + // from executing when they are loaded. + $url = $this->url; + if ($this->setting_val(CrayonSettings::DECODE_ATTRIBUTES)) { + $url = CrayonUtil::html_entity_decode($url); + } + $url = CrayonUtil::pathf($url); + $site_http = CrayonGlobalSettings::site_url(); + $scheme = parse_url($url, PHP_URL_SCHEME); + // Try to replace the site URL with a path to force local loading + if (empty($scheme)) { + // No url scheme is given - path may be given as relative + $url = CrayonUtil::path_slash($site_http) . CrayonUtil::path_slash($this->setting_val(CrayonSettings::LOCAL_PATH)) . $url; + } + $http_code = 0; + // If available, use the built in wp remote http get function. + if (function_exists('wp_remote_get')) { + $url_uid = 'crayon_' . CrayonUtil::str_uid($url); + $cached = get_transient($url_uid, 'crayon-syntax'); + CrayonSettingsWP::load_cache(); + if ($cached !== FALSE) { + $content = $cached; + $http_code = 200; + } else { + $response = @wp_remote_get($url, array('sslverify' => false, 'timeout' => 20)); + $content = wp_remote_retrieve_body($response); + $http_code = wp_remote_retrieve_response_code($response); + $cache = $this->setting_val(CrayonSettings::CACHE); + $cache_sec = CrayonSettings::get_cache_sec($cache); + if ($cache_sec > 1 && $http_code >= 200 && $http_code < 400) { + set_transient($url_uid, $content, $cache_sec); + CrayonSettingsWP::add_cache($url_uid); + } + } + } else if (in_array(parse_url($url, PHP_URL_SCHEME), array('ssl', 'http', 'https'))) { + // Fallback to cURL. At this point, the URL scheme must be valid. + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + // For https connections, we do not require SSL verification + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); + curl_setopt($ch, CURLOPT_FRESH_CONNECT, FALSE); + curl_setopt($ch, CURLOPT_MAXREDIRS, 5); + if (isset($_SERVER['HTTP_USER_AGENT'])) { + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); + } + $content = curl_exec($ch); + $error = curl_error($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + } + if ($http_code >= 200 && $http_code < 400) { + $this->code($content); + } else { + if (empty($this->code)) { + // If code is also given, just use that + $this->error("The provided URL ('$this->url'), parsed remotely as ('$url'), could not be accessed."); + } + } + $this->needs_load = FALSE; + } + + /* Central point of access for all other functions to update code. */ + public function process() { + $tmr = new CrayonTimer(); + $this->runtime = NULL; + if ($this->needs_load) { + $tmr->start(); + $this->load(); + $this->runtime[CRAYON_LOAD_TIME] = $tmr->stop(); + } + if (!empty($this->error) || empty($this->code)) { + // Disable highlighting for errors and empty code + return; + } + + if ($this->language === NULL) { + $this->language_detect(); + } + if ($this->needs_format) { + $tmr->start(); + try { + // Parse before hand to read modes + $code = $this->code; + // If inline, then combine lines into one + if ($this->is_inline) { + $code = preg_replace('#[\r\n]+#ms', '', $code); + if ($this->setting_val(CrayonSettings::TRIM_WHITESPACE)) { + $code = trim($code); + } + } + // Decode html entities (e.g. if using visual editor or manually encoding) + if ($this->setting_val(CrayonSettings::DECODE)) { + $code = CrayonUtil::html_entity_decode($code); + } + // Save code so output is plain output is the same + $this->code = $code; + + // Allow mixed if langauge supports it and setting is set + CrayonParser::parse($this->language->id()); + if (!$this->setting_val(CrayonSettings::MIXED) || !$this->language->mode(CrayonParser::ALLOW_MIXED)) { + // Format the code with the generated regex and elements + $this->formatted_code = CrayonFormatter::format_code($code, $this->language, $this); + } else { + // Format the code with Mixed Highlighting + $this->formatted_code = CrayonFormatter::format_mixed_code($code, $this->language, $this); + } + } catch (Exception $e) { + $this->error($e->message()); + return; + } + $this->needs_format = FALSE; + $this->runtime[CRAYON_FORMAT_TIME] = $tmr->stop(); + } + } + + /* Used to format the glue in between code when finding mixed languages */ + private function format_glue($glue, $highlight = TRUE) { + // TODO $highlight + return CrayonFormatter::format_code($glue, $this->language, $this, $highlight); + } + + /* Sends the code to the formatter for printing. Apart from the getters and setters, this is + the only other function accessible outside this class. $show_lines can also be a string. */ + function output($show_lines = TRUE, $print = TRUE) { + $this->process(); + if (empty($this->error)) { + // If no errors have occured, print the formatted code + $ret = CrayonFormatter::print_code($this, $this->formatted_code, $show_lines, $print); + } else { + $ret = CrayonFormatter::print_error($this, $this->error, '', $print); + } + // Reset the error message at the end of the print session + $this->error = ''; + // If $print = FALSE, $ret will contain the output + return $ret; + } + + // Getters and Setters ==================================================== + function code($code = NULL) { + if ($code === NULL) { + return $this->code; + } else { + // Trim whitespace + if ($this->setting_val(CrayonSettings::TRIM_WHITESPACE)) { + $code = preg_replace("#(?:^\\s*\\r?\\n)|(?:\\r?\\n\\s*$)#", '', $code); + } + + if ($this->setting_val(CrayonSettings::TRIM_CODE_TAG)) { + $code = preg_replace('#^\s*<\s*code[^>]*>#msi', '', $code); + $code = preg_replace('#]*>\s*$#msi', '', $code); + } + + $before = $this->setting_val(CrayonSettings::WHITESPACE_BEFORE); + if ($before > 0) { + $code = str_repeat("\n", $before) . $code; + } + $after = $this->setting_val(CrayonSettings::WHITESPACE_AFTER); + if ($after > 0) { + $code = $code . str_repeat("\n", $after); + } + + if (!empty($code)) { + $this->code = $code; + $this->needs_format = TRUE; + } + } + } + + function language($id = NULL) { + if ($id === NULL || !is_string($id)) { + return $this->language; + } + + if ( ($lang = CrayonResources::langs()->get($id)) != FALSE || ($lang = CrayonResources::langs()->alias($id)) != FALSE ) { + // Set the language if it exists or look for an alias + $this->language = $lang; + } else { + $this->language_detect(); + } + + // Prepare the language for use, even if we have no code, we need the name + CrayonParser::parse($this->language->id()); + } + + function language_detect() { + // Attempt to detect the language + if (!empty($id)) { + $this->log("The language '$id' could not be loaded."); + } + $this->language = CrayonResources::langs()->detect($this->url, $this->setting_val(CrayonSettings::FALLBACK_LANG)); + } + + function url($url = NULL) { + if ($url === NULL) { + return $this->url; + } else { + $this->url = $url; + $this->needs_load = TRUE; + } + } + + function title($title = NULL) { + if (!CrayonUtil::str($this->title, $title)) { + return $this->title; + } + } + + function line_count($line_count = NULL) { + if (!CrayonUtil::num($this->line_count, $line_count)) { + return $this->line_count; + } + } + + function marked($str = NULL) { + if ($str === NULL) { + return $this->marked_lines; + } + // If only an int is given + if (is_int($str)) { + $array = array($str); + return CrayonUtil::arr($this->marked_lines, $array); + } + // A string with ints separated by commas, can also contain ranges + $array = CrayonUtil::trim_e($str); + $array = array_unique($array); + $lines = array(); + foreach ($array as $line) { + // Check for ranges + if (strpos($line, '-') !== FALSE) { + $ranges = CrayonUtil::range_str($line); + $lines = array_merge($lines, $ranges); + } else { + // Otherwise check the string for a number + $line = intval($line); + if ($line !== 0) { + $lines[] = $line; + } + } + } + return CrayonUtil::arr($this->marked_lines, $lines); + } + + function range($str = NULL) { + if ($str === NULL) { + return $this->range; + } else { + $range = CrayonUtil::range_str_single($str); + if ($range) { + $this->range = $range; + } + } + return FALSE; + } + + function log($var) { + if ($this->setting_val(CrayonSettings::ERROR_LOG)) { + CrayonLog::log($var); + } + } + + function id($id = NULL) { + if ($id == NULL) { + return $this->id; + } else { + $this->id = strval($id); + } + } + + function error($string = NULL) { + if (!$string) { + return $this->error; + } + $this->error .= $string; + $this->log($string); + // Add the error string and ensure no further processing occurs + $this->needs_load = FALSE; + $this->needs_format = FALSE; + } + + // Set and retreive settings + // TODO fix this, it's too limiting + function settings($mixed = NULL) { + if ($this->settings == NULL) { + $this->settings = CrayonGlobalSettings::get_obj(); + } + + if ($mixed === NULL) { + return $this->settings; + } else if (is_string($mixed)) { + return $this->settings->get($mixed); + } else if (is_array($mixed)) { + $this->settings->set($mixed); + return TRUE; + } + return FALSE; + } + + /* Retrieve a single setting's value for use in the formatter. By default, on failure it will + * return TRUE to ensure FALSE is only sent when a setting is found. This prevents a fake + * FALSE when the formatter checks for a positive setting (Show/Enable) and fails. When a + * negative setting is needed (Hide/Disable), $default_return should be set to FALSE. */ + // TODO fix this (see above) + function setting_val($name = NULL, $default_return = TRUE) { + if (is_string($name) && $setting = $this->settings($name)) { + return $setting->value(); + } else { + // Name not valid + return (is_bool($default_return) ? $default_return : TRUE); + } + } + + // Set a setting value + // TODO fix this (see above) + function setting_set($name = NULL, $value = TRUE) { + $this->settings->set($name, $value); + } + + // Used to find current index in dropdown setting + function setting_index($name = NULL) { + $setting = $this->settings($name); + if (is_string($name) && $setting->is_array()) { + return $setting->index(); + } else { + // Returns -1 to avoid accidentally selecting an item in a dropdown + return CrayonSettings::INVALID; + } + } + + function formatted_code() { + return $this->formatted_code; + } + + function runtime() { + return $this->runtime; + } + + function is_highlighted($highlighted = NULL) { + if ($highlighted === NULL) { + return $this->is_highlighted; + } else { + $this->is_highlighted = $highlighted; + } + } + + function is_mixed($mixed = NULL) { + if ($mixed === NULL) { + return $this->is_mixed; + } else { + $this->is_mixed = $mixed; + } + } + + function is_inline($inline = NULL) { + if ($inline === NULL) { + return $this->is_inline; + } else { + $inline = CrayonUtil::str_to_bool($inline, FALSE); + $this->is_inline = $inline; + } + } +} +?> \ No newline at end of file diff --git a/crayon_langs.class.php b/crayon_langs.class.php new file mode 100644 index 0000000..ee6c156 --- /dev/null +++ b/crayon_langs.class.php @@ -0,0 +1,544 @@ + 'c', 'PREPROCESSOR' => 'p', 'STRING' => 's', 'KEYWORD' => 'k', + 'STATEMENT' => 'st', 'RESERVED' => 'r', 'TYPE' => 't', 'TAG' => 'ta', 'MODIFIER' => 'm', 'IDENTIFIER' => 'i', + 'ENTITY' => 'e', 'VARIABLE' => 'v', 'CONSTANT' => 'cn', 'OPERATOR' => 'o', 'SYMBOL' => 'sy', + 'NOTATION' => 'n', 'FADED' => 'f', CrayonParser::HTML_CHAR => 'h', CrayonParser::CRAYON_ELEMENT => 'crayon-internal-element'); + const DEFAULT_LANG = 'default'; + const DEFAULT_LANG_NAME = 'Default'; + + const RESOURCE_TYPE = 'CrayonLangsResourceType'; + + // Used to cache the objects, since they are unlikely to change during a single run + private static $resource_cache = array(); + + // Methods ================================================================ + public function __construct() { + $this->set_default(self::DEFAULT_LANG, self::DEFAULT_LANG_NAME); + $this->directory(CRAYON_LANG_PATH); + $this->relative_directory(CRAYON_LANG_DIR); + $this->extension('txt'); + + CrayonLog::debug("Setting lang directories"); + $upload = CrayonGlobalSettings::upload_path(); + if ($upload) { + $this->user_directory($upload . CRAYON_LANG_DIR); + if (!is_dir($this->user_directory())) { + CrayonGlobalSettings::mkdir($this->user_directory()); + CrayonLog::debug($this->user_directory(), "LANG USER DIR"); + } + } else { + CrayonLog::syslog("Upload directory is empty: " . $upload . " cannot load languages."); + } + CrayonLog::debug($this->directory()); + CrayonLog::debug($this->user_directory()); + } + + public function filename($id, $user = NULL) { + return $id."/$id.".$this->extension(); + } + + // XXX Override + public function load_process() { + parent::load_process(); + $this->load_exts(); + $this->load_aliases(); + $this->load_delimiters(); // TODO check for setting? + } + + public function load_resources($dir = NULL) { + parent::load_resources($dir); + + } + + // XXX Override + public function create_user_resource_instance($id, $name = NULL) { + return new CrayonLang($id, $name); + } + + // XXX Override + public function add_default() { + $result = parent::add_default(); + if ($this->is_state_loading() && !$result) { + // Default not added, must already be loaded, ready to parse + CrayonParser::parse(self::DEFAULT_LANG); + } + } + + /* Attempts to detect the language based on extension, otherwise falls back to fallback language given. + * Returns a CrayonLang object. */ + public function detect($path, $fallback_id = NULL) { + $this->load(); + extract(pathinfo($path)); + + // If fallback id if given + if ($fallback_id == NULL) { + // Otherwise use global fallback + $fallback_id = CrayonGlobalSettings::get(CrayonSettings::FALLBACK_LANG); + } + // Attempt to use fallback + $fallback = $this->get($fallback_id); + // Use extension before trying fallback + $extension = isset($extension) ? $extension : ''; + + if ( !empty($extension) && ($lang = $this->ext($extension)) || ($lang = $this->get($extension)) ) { + // If extension is found, attempt to find a language for it. + // If that fails, attempt to load a language with the same id as the extension. + return $lang; + } else if ($fallback != NULL || $fallback = $this->get_default()) { + // Resort to fallback if loaded, or fallback to default + return $fallback; + } else { + // No language found + return NULL; + } + } + + /* Load all extensions and add them into each language. */ + private function load_exts() { + // Load only once + if (!$this->is_state_loading()) { + return; + } + if ( ($lang_exts = self::load_attr_file(CRAYON_LANG_EXT)) !== FALSE ) { + foreach ($lang_exts as $lang_id=>$exts) { + $lang = $this->get($lang_id); + $lang->ext($exts); + } + } + } + + /* Load all extensions and add them into each language. */ + private function load_aliases() { + // Load only once + if (!$this->is_state_loading()) { + return; + } + if ( ($lang_aliases = self::load_attr_file(CRAYON_LANG_ALIAS)) !== FALSE ) { + foreach ($lang_aliases as $lang_id=>$aliases) { + $lang = $this->get($lang_id); + $lang->alias($aliases); + } + } + } + + /* Load all extensions and add them into each language. */ + private function load_delimiters() { + // Load only once + if (!$this->is_state_loading()) { + return; + } + if ( ($lang_delims = self::load_attr_file(CRAYON_LANG_DELIM)) !== FALSE ) { + foreach ($lang_delims as $lang_id=>$delims) { + $lang = $this->get($lang_id); + $lang->delimiter($delims); + } + } + } + + // Used to load aliases and extensions to languages + private function load_attr_file($path) { + if ( ($lines = CrayonUtil::lines($path, 'lwc')) !== FALSE) { + $attributes = array(); // key = language id, value = array of attr + foreach ($lines as $line) { + preg_match('#^[\t ]*([^\r\n\t ]+)[\t ]+([^\r\n]+)#', $line, $matches); + if (count($matches) == 3 && $lang = $this->get($matches[1])) { + // If the langauges of the attribute exists, return it in an array + // TODO merge instead of replace key? + $attributes[$matches[1]] = explode(' ', $matches[2]); + } + } + return $attributes; + } else { + CrayonLog::syslog('Could not load attr file: ' . $path); + return FALSE; + } + } + + /* Returns the CrayonLang for the given extension */ + public function ext($ext) { + $this->load(); + foreach ($this->get() as $lang) { + if ($lang->has_ext($ext)) { + return $lang; + } + } + return FALSE; + } + + /* Returns the CrayonLang for the given alias */ + public function alias($alias) { + $this->load(); + foreach ($this->get() as $lang) { + if ($lang->has_alias($alias)) { + return $lang; + } + } + return FALSE; + } + + /* Fetches a resource. Type is an int from CrayonLangsResourceType. */ + public function fetch($type, $reload = FALSE, $keep_empty_fetches = FALSE) { + $this->load(); + + if (!array_key_exists($type, self::$resource_cache) || $reload) { + $fetches = array(); + foreach ($this->get() as $lang) { + + switch ($type) { + case CrayonLangsResourceType::EXTENSION: + $fetch = $lang->ext(); + break; + case CrayonLangsResourceType::ALIAS: + $fetch = $lang->alias(); + break; + case CrayonLangsResourceType::DELIMITER: + $fetch = $lang->delimiter(); + break; + default: + return FALSE; + } + + if ( !empty($fetch) || $keep_empty_fetches ) { + $fetches[$lang->id()] = $fetch; + } + } + self::$resource_cache[$type] = $fetches; + } + return self::$resource_cache[$type]; + } + + public function extensions($reload = FALSE) { + return $this->fetch(CrayonLangsResourceType::EXTENSION, $reload); + } + + public function aliases($reload = FALSE) { + return $this->fetch(CrayonLangsResourceType::ALIAS, $reload); + } + + public function delimiters($reload = FALSE) { + return $this->fetch(CrayonLangsResourceType::DELIMITER, $reload); + } + + public function extensions_inverted($reload = FALSE) { + $extensions = $this->extensions($reload); + $inverted = array(); + foreach ($extensions as $lang=>$exts) { + foreach ($exts as $ext) { + $inverted[$ext] = $lang; + } + } + return $inverted; + } + + public function ids_and_aliases($reload = FALSE) { + $fetch = $this->fetch(CrayonLangsResourceType::ALIAS, $reload, TRUE); + foreach ($fetch as $id=>$alias_array) { + $ids_and_aliases[] = $id; + foreach ($alias_array as $alias) { + $ids_and_aliases[] = $alias; + } + } + return $ids_and_aliases; + } + + /* Return the array of valid elements or a particular element value */ + public static function known_elements($name = NULL) { + if ($name === NULL) { + return self::$known_elements; + } else if (is_string($name) && array_key_exists($name, self::$known_elements)) { + return self::$known_elements[$name]; + } else { + return FALSE; + } + } + + /* Verify an element is valid */ + public static function is_known_element($name) { + return self::known_elements($name) !== FALSE; + } + + /* Compare two languages by name */ + public static function langcmp($a, $b) { + $a = strtolower($a->name()); + $b = strtolower($b->name()); + if ($a == $b) { + return 0; + } else { + return ($a < $b) ? -1 : 1; + } + } + + public static function sort_by_name($langs) { + // Sort by name + usort($langs, 'CrayonLangs::langcmp'); + $sorted_lags = array(); + foreach ($langs as $lang) { + $sorted_lags[$lang->id()] = $lang; + } + return $sorted_lags; + } + + public function is_parsed($id = NULL) { + if ($id === NULL) { + // Determine if all langs are successfully parsed + foreach ($this->get() as $lang) { + if ($lang->state() != CrayonLang::PARSED_SUCCESS) { + return FALSE; + } + } + return TRUE; + } else if (($lang = $this->get($id)) != FALSE) { + return $lang->is_parsed(); + } + return FALSE; + } + + public function is_default($id) { + if (($lang = $this->get($id)) != FALSE) { + return $lang->is_default(); + } + return FALSE; + } +} + +/* Individual language. */ +class CrayonLang extends CrayonVersionResource { + private $ext = array(); + private $aliases = array(); + private $delimiters = ''; + // Associative array of CrayonElement objects + private $elements = array(); + //private $regex = ''; + private $state = self::UNPARSED; + private $modes = array(); + // Whether this language allows Multiple Highlighting from other languages + const PARSED_ERRORS = -1; + const UNPARSED = 0; + const PARSED_SUCCESS = 1; + + function __construct($id, $name = NULL) { + parent::__construct($id, $name); + $this->modes = CrayonParser::modes(); + } + + // Override + function clean_id($id) { + $id = CrayonUtil::space_to_hyphen( strtolower(trim($id)) ); + return preg_replace('/[^\w\-+#]/msi', '', $id); + } + + function ext($ext = NULL) { + if ($ext === NULL) { + return $this->ext; + } else if (is_array($ext) && !empty($ext)) { + foreach ($ext as $e) { + $this->ext($e); + } + } else if (is_string($ext) && !empty($ext) && !in_array($ext, $this->ext)) { + $ext = strtolower($ext); + $ext = str_replace('.', '', $ext); + $this->ext[] = $ext; + } + } + + function has_ext($ext) { + return is_string($ext) && in_array($ext, $this->ext); + } + + function alias($alias = NULL) { + if ($alias === NULL) { + return $this->aliases; + } else if (is_array($alias) && !empty($alias)) { + foreach ($alias as $a) { + $this->alias($a); + } + } else if (is_string($alias) && !empty($alias) && !in_array($alias, $this->aliases)) { + $alias = strtolower($alias); + $this->aliases[] = $alias; + } + } + + function has_alias($alias) { + return is_string($alias) && in_array($alias, $this->aliases); + } + + function delimiter($delim = NULL) { + if ($delim === NULL) { + return $this->delimiters; + // Convert to regex for capturing delimiters + } else if (is_string($delim) && !empty($delim)) { + $this->delimiters = '(?:'.$delim.')'; + } else if (is_array($delim) && !empty($delim)) { + for ($i = 0; $i < count($delim); $i++) { + $delim[$i] = CrayonUtil::esc_atomic($delim[$i]); + } + + $this->delimiters = '(?:'.implode(')|(?:', $delim).')'; + } + } + + function regex($element = NULL) { + if ($element == NULL) { + $regexes = array(); + foreach ($this->elements as $element) { + $regexes[] = $element->regex(); + } + return '#' . '(?:('. implode(')|(', array_values($regexes)) . '))' . '#' . + ($this->mode(CrayonParser::CASE_INSENSITIVE) ? 'i' : '') . + ($this->mode(CrayonParser::MULTI_LINE) ? 'm' : '') . + ($this->mode(CrayonParser::SINGLE_LINE) ? 's' : ''); + } else if (is_string($element) && array_key_exists($element, $this->elements)) { + return $this->elements[$element]->regex(); + } + } + + // Retrieve by element name or set by CrayonElement + function element($name, $element = NULL) { + if (is_string($name)) { + $name = trim(strtoupper($name)); + if (array_key_exists($name, $this->elements) && $element === NULL) { + return $this->elements[$name]; + } else if (@get_class($element) == CRAYON_ELEMENT_CLASS) { + $this->elements[$name] = $element; + } + } + } + + function elements() { + return $this->elements; + } + + function mode($name = NULL, $value = NULL) { + if (is_string($name) && CrayonParser::is_mode($name)) { + $name = trim(strtoupper($name)); + if ($value == NULL && array_key_exists($name, $this->modes)) { + return $this->modes[$name]; + } else if (is_string($value)) { + if (CrayonUtil::str_equal_array(trim($value), array('ON', 'YES', '1'))) { + $this->modes[$name] = TRUE; + } else if (CrayonUtil::str_equal_array(trim($value), array('OFF', 'NO', '0'))) { + $this->modes[$name] = FALSE; + } + } + } else { + return $this->modes; + } + } + + function state($state = NULL) { + if ($state === NULL) { + return $this->state; + } else if (is_int($state)) { + if ($state < 0) { + $this->state = self::PARSED_ERRORS; + } else if ($state > 0) { + $this->state = self::PARSED_SUCCESS; + } else if ($state == 0) { + $this->state = self::UNPARSED; + } + } + } + + function state_info() { + switch ($this->state) { + case self::PARSED_ERRORS : + return 'Parsed With Errors'; + case self::PARSED_SUCCESS : + return 'Successfully Parsed'; + case self::UNPARSED : + return 'Not Parsed'; + default : + return 'Undetermined'; + } + } + + function is_parsed() { + return ($this->state != self::UNPARSED); + } + + function is_default() { + return $this->id() == CrayonLangs::DEFAULT_LANG; + } +} + +class CrayonElement { + // The pure regex syntax without any modifiers or delimiters + private $name = ''; + private $css = ''; + private $regex = ''; + private $fallback = ''; + private $path = ''; + + function __construct($name, $path, $regex = '') { + $this->name($name); + $this->path($path); + $this->regex($regex); + } + + function __toString() { + return $this->regex(); + } + + function name($name = NULL) { + if ($name == NULL) { + return $this->name; + } else if (is_string($name)) { + $name = trim(strtoupper($name)); + if (CrayonLangs::is_known_element($name)) { + // If known element, set CSS to known class + $this->css(CrayonLangs::known_elements($name)); + } + $this->name = $name; + } + } + + function regex($regex = NULL) { + if ($regex == NULL) { + return $this->regex; + } else if (is_string($regex)) { + if (($result = CrayonParser::validate_regex($regex, $this)) !== FALSE) { + $this->regex = $result; + } else { + return FALSE; + } + } + } + + // Expects: 'class1 class2 class3' + function css($css = NULL) { + if ($css == NULL) { + return $this->css; + } else if (is_string($css)) { + $this->css = CrayonParser::validate_css($css); + } + } + + function fallback($fallback = NULL) { + if ($fallback == NULL) { + return $this->fallback; + } else if (is_string($fallback) && CrayonLangs::is_known_element($fallback)) { + $this->fallback = $fallback; + } + } + + function path($path = NULL) { + if ($path == NULL) { + return $this->path; + } else if (is_string($path) && @file_exists($path)) { + $this->path = $path; + } + } +} \ No newline at end of file diff --git a/crayon_parser.class.php b/crayon_parser.class.php new file mode 100644 index 0000000..44a2ede --- /dev/null +++ b/crayon_parser.class.php @@ -0,0 +1,265 @@ +)'; // No longer used + const HTML_CHAR = 'HTML_CHAR'; + const HTML_CHAR_REGEX = '<|>|(&([\w-]+);?)|[ \t]+'; + const CRAYON_ELEMENT = 'CRAYON_ELEMENT'; + const CRAYON_ELEMENT_REGEX = '\{\{crayon-internal:[^\}]*\}\}'; + const CRAYON_ELEMENT_REGEX_CAPTURE = '\{\{crayon-internal:([^\}]*)\}\}'; + + private static $modes = array(self::CASE_INSENSITIVE => TRUE, self::MULTI_LINE => TRUE, self::SINGLE_LINE => TRUE, self::ALLOW_MIXED => TRUE); + + // Methods ================================================================ + private function __construct() {} + + /** + * Parse all languages stored in CrayonLangs. + * Avoid using this unless you must list the details in language files for all languages. + * @return array Array of all loaded CrayonLangs. + */ + public static function parse_all() { + $langs = CrayonResources::langs()->get(); + if (empty($langs)) { + return FALSE; + } + foreach ($langs as $lang) { + self::parse($lang->id()); + } + return $langs; + } + + /* Read a syntax file and parse the regex rules within it, this may require several other + files containing lists of keywords and such to be read. Updates the parsed elements and + regex in the CrayonLang with the given $id. */ + public static function parse($id) { + // Verify the language is loaded and has not been parsed before + if ( !($lang = CrayonResources::langs()->get($id)) ) { + CrayonLog::syslog("The language with id '$id' was not loaded and could not be parsed."); + return FALSE; + } else if ($lang->is_parsed()) { + return; + } + // Read language file + $path = CrayonResources::langs()->path($id); + CrayonLog::debug('Parsing language ' . $path); + if ( ($file = CrayonUtil::lines($path, 'wcs')) === FALSE ) { + CrayonLog::debug('Parsing failed ' . $path); + return FALSE; + } + + // Extract the language name + $name_pattern = '#^[ \t]*name[ \t]+([^\r\n]+)[ \t]*#mi'; + preg_match($name_pattern, $file, $name); + if (count($name) > 1) { + $name = $name[1]; + $lang->name($name); + $file = preg_replace($name_pattern, '', $file); + } else { + $name = $lang->id(); + } + + // Extract the language version + $version_pattern = '#^[ \t]*version[ \t]+([^\r\n]+)[ \t]*#mi'; + preg_match($version_pattern, $file, $version); + if (count($version) > 1) { + $version = $version[1]; + $lang->version($version); + $file = preg_replace($version_pattern, '', $file); + } + + // Extract the modes + $mode_pattern = '#^[ \t]*(' . implode('|', array_keys(self::$modes)) . ')[ \t]+(?:=[ \t]*)?([^\r\n]+)[ \t]*#mi'; + preg_match_all($mode_pattern, $file, $mode_matches); + if (count($mode_matches) == 3) { + for ($i = 0; $i < count($mode_matches[0]); $i++) { + $lang->mode($mode_matches[1][$i], $mode_matches[2][$i]); + } + $file = preg_replace($mode_pattern, '', $file); + } + + /* Add reserved Crayon element. This is used by Crayon internally. */ + $crayon_element = new CrayonElement(self::CRAYON_ELEMENT, $path, self::CRAYON_ELEMENT_REGEX); + $lang->element(self::CRAYON_ELEMENT, $crayon_element); + + // Extract elements, classes and regex + $pattern = '#^[ \t]*([\w:]+)[ \t]+(?:\[([\w\t ]*)\][ \t]+)?([^\r\n]+)[ \t]*#m'; + preg_match_all($pattern, $file, $matches); + + if (!empty($matches[0])) { + $elements = $matches[1]; + $classes = $matches[2]; + $regexes = $matches[3]; + } else { + CrayonLog::syslog("No regex patterns and/or elements were parsed from language file at '$path'."); + } + + // Remember state in case we encounter catchable exceptions + $error = FALSE; + for ($i = 0; $i < count($matches[0]); $i++) { + // References + $name = &$elements[$i]; + $class = &$classes[$i]; + $regex = &$regexes[$i]; + $name = trim(strtoupper($name)); + // Ensure both the element and regex are valid + if (empty($name) || empty($regex)) { + CrayonLog::syslog("Element(s) and/or regex(es) are missing in '$path'."); + $error = TRUE; + continue; + } + // Look for fallback element + $pieces = explode(':', $name); + if (count($pieces) == 2) { + $name = $pieces[0]; + $fallback = $pieces[1]; + } else if (count($pieces) == 1) { + $name = $pieces[0]; + $fallback = ''; + } else { + CrayonLog::syslog("Too many colons found in element name '$name' in '$path'"); + $error = TRUE; + continue; + } + // Create a new CrayonElement + $element = new CrayonElement($name, $path); + $element->fallback($fallback); + if (!empty($class)) { + // Avoid setting known css to blank + $element->css($class); + } + if ($element->regex($regex) === FALSE) { + $error = TRUE; + continue; + } + // Add the regex to the element + $lang->element($name, $element); + $state = $error ? CrayonLang::PARSED_ERRORS : CrayonLang::PARSED_SUCCESS; + $lang->state($state); + } + + /* Prevents < > and other html entities from being printed as is, which could lead to actual html tags + * from the printed code appearing on the page - not good. This can also act to color any HTML entities + * that are not picked up by previously defined elements. + */ + $html = new CrayonElement(self::HTML_CHAR, $path, self::HTML_CHAR_REGEX); + $lang->element(self::HTML_CHAR, $html); + } + + // Validates regex and accesses data stored in a CrayonElement + public static function validate_regex($regex, $element) { + if (is_string($regex) && @get_class($element) == CRAYON_ELEMENT_CLASS) { + // If the (?alt) tag has been used, insert the file into the regex + $file = self::regex_match('#\(\?alt:(.+?)\)#', $regex); + if ( count($file) == 2 ) { + // Element 0 has full match, 1 has captured groups + for ($i = 0; $i < count($file[1]); $i++) { + $file_lines = CrayonUtil::lines(dirname($element->path()) . crayon_s() . $file[1][$i], 'rcwh'); + if ($file_lines !== FALSE) { + $file_lines = implode('|', $file_lines); + // If any spaces exist, treat them as whitespace + $file_lines = preg_replace('#[ \t]+#msi', '\s+', $file_lines); + $regex = str_replace($file[0][$i], "(?:$file_lines)", $regex); + } else { + CrayonLog::syslog("Parsing of '{$element->path()}' failed, an (?alt) tag failed for the element '{$element->name()}'" ); + return FALSE; + } + } + } + + // If the (?default:element) function is used, replace the regex with the default, if exists + $def = self::regex_match('#\(\?default(?:\:(\w+))?\)#', $regex); + if ( count($def) == 2 ) { + // Load default language + $default = CrayonResources::langs()->get(CrayonLangs::DEFAULT_LANG); + // If default has not been loaded, we can't use it, skip the element + if (!$default) { + CrayonLog::syslog( + "Could not use default regex in the element '{$element->name()}' in '{$element->path()}'"); + return FALSE; + } + for ($i = 0; $i < count($def[1]); $i++) { + // If an element has been provided + $element_name = ( !empty($def[1][$i]) ) ? $def[1][$i] : $element->name(); + if (($default_element = $default->element($element_name)) != FALSE) { + $regex = str_replace($def[0][$i], '(?:' . $default_element->regex() .')', $regex); + } else { + CrayonLog::syslog("The language at '{$element->path()}' referred to the Default Language regex for element '{$element->name()}', which did not exist."); + if (CRAYON_DEBUG) { + CrayonLog::syslog("Default language URL: " . CrayonResources::langs()->url(CrayonLangs::DEFAULT_LANG)); + CrayonLog::syslog("Default language Path: " . CrayonResources::langs()->path(CrayonLangs::DEFAULT_LANG)); + } + return FALSE; + } + } + } + + // If the (?html) tag is used, escape characters in html (<, > and &) + $html = self::regex_match('#\(\?html:(.+?)\)#', $regex); + if ( count($html) == 2 ) { + for ($i = 0; $i < count($html[1]); $i++) { + $regex = str_replace($html[0][$i], htmlentities($html[1][$i]), $regex); + } + } + + // Ensure all parenthesis are atomic to avoid conflicting with element matches + $regex = CrayonUtil::esc_atomic($regex); + + // Escape #, this is our delimiter + $regex = CrayonUtil::esc_hash($regex); + + // Test if regex is valid + if (@preg_match("#$regex#", '') === FALSE) { + CrayonLog::syslog("The regex for the element '{$element->name()}' in '{$element->path()}' is not valid."); + return FALSE; + } + + return $regex; + } else { + return ''; + } + } + + public static function validate_css($css) { + if (is_string($css)) { + // Remove dots in CSS class and convert to lowercase + $css = str_replace('.', '', $css); + $css = strtolower($css); + $css = explode(' ', $css); + $css_str = ''; + foreach ($css as $c) { + if (!empty($c)) { + $css_str .= $c . ' '; + } + } + return trim($css_str); + } else { + return ''; + } + } + + public static function regex_match($pattern, $subject) { + if (preg_match_all($pattern, $subject, $matches)) { + return $matches; + } + return array(); + } + + public static function modes() { + return self::$modes; + } + + public static function is_mode($name) { + return is_string($name) && array_key_exists($name, self::$modes); + } +} +?> \ No newline at end of file diff --git a/crayon_resource.class.php b/crayon_resource.class.php new file mode 100644 index 0000000..03df8e2 --- /dev/null +++ b/crayon_resource.class.php @@ -0,0 +1,478 @@ +path($id)); + } + + /* Load all the available languages. Doesn't parse them for their names and regex. */ + public function load() { + // Load only once + + if (!$this->is_state_unloaded()) { + return; + } + $this->state = self::LOADING; + $this->load_process(); + $this->state = self::LOADED; + } + + public function load_resources($dir = NULL) { + if ($dir === NULL) { + $dir = $this->dir; + } + + if (!$this->is_state_loading()) { + // Load only once + return; + } + try { + // Look in directory for resources + + if (!is_dir($dir)) { + CrayonLog::syslog('The resource directory is missing, should be at \'' . $dir . '\'.'); + } else if (($handle = @opendir($dir)) != FALSE) { + // Loop over directory contents + while (($file = readdir($handle)) !== FALSE) { + if ($file != "." && $file != "..") { + // Check if $file is directory, remove extension when checking for existence. + + if (!is_dir($dir . $file)) { + $file = CrayonUtil::path_rem_ext($file); + } + if ($this->exists($file)) { + $this->add_resource($this->resource_instance($file)); + } + } + } + closedir($handle); + } + } catch (Exception $e) { + CrayonLog::syslog('An error occured when trying to load resources: ' . $e->getFile() . $e->getLine()); + } + } + + /* Override in subclasses. */ + public function load_process() { + if (!$this->is_state_loading()) { + return; + } + $this->load_resources(); + $this->add_default(); + } + + /* Override in subclasses */ + public function add_default() { + if (!$this->is_state_loading()) { + return FALSE; + } else if (!$this->is_loaded($this->default_id)) { + CrayonLog::syslog('The default resource could not be loaded from \'' . $this->dir . '\'.'); + // Add the default, but it will not be functionable + + $default = $this->resource_instance($this->default_id, $this->default_name); + $this->add($this->default_id, $default); + return TRUE; + } + return FALSE; + } + + /* Returns the default resource */ + public function set_default($id, $name) { + $this->default_id = $id; + $this->default_name = $name; + } + + /* Returns the default resource */ + public function get_default() { + return $this->get($this->default_id); + } + + /* Override in subclasses to create subclass object if needed */ + public function resource_instance($id, $name = NULL) { + return new CrayonResource($id, $name); + } + + public function add($id, $resource) { + if (is_string($id) && !empty($id)) { + $this->collection[$id] = $resource; + asort($this->collection); + CrayonLog::debug('Added resource: ' . $this->path($id)); + } else { + CrayonLog::syslog('Could not add resource: ', $id); + } + } + + public function add_resource($resource) { + $this->add($resource->id(), $resource); + } + + public function remove($name) { + if (is_string($name) && !empty($name) && array_key_exists($name, $this->collection)) { + unset($this->collection[$name]); + } + } + + public function remove_all() { + $this->collection = array(); + } + + /* Returns the resource for the given id or NULL if it can't be found */ + public function get($id = NULL) { + $this->load(); + if ($id === NULL) { + return $this->collection; + } else if (is_string($id) && $this->is_loaded($id)) { + return $this->collection[$id]; + } + return NULL; + } + + public function get_array() { + $array = array(); + foreach ($this->get() as $resource) { + $array[$resource->id()] = $resource->name(); + } + return $array; + } + + public function is_loaded($id) { + if (is_string($id)) { + return array_key_exists($id, $this->collection); + } + return FALSE; + } + + public function get_state() { + return $this->state; + } + + public function is_state_loaded() { + return $this->state == self::LOADED; + } + + public function is_state_loading() { + return $this->state == self::LOADING; + } + + public function is_state_unloaded() { + return $this->state == self::UNLOADED; + } + + public function directory($dir = NULL) { + if ($dir === NULL) { + return $this->dir; + } else { + $this->dir = CrayonUtil::path_slash($dir); + } + } + + public function url($id) { + return ''; + } + + public function get_css($id, $ver = NULL) { + $resource = $this->get($id); + return '' . CRAYON_NL; + } +} + +class CrayonUsedResourceCollection extends CrayonResourceCollection { + + // Checks if any resoruces are being used + public function is_used($id = NULL) { + if ($id === NULL) { + foreach ($this->get() as $resource) { + if ($resource->used()) { + return TRUE; + } + } + return FALSE; + } else { + $resource = $this->get($id); + if (!$resource) { + return FALSE; + } else { + return $resource->used(); + } + } + } + + public function set_used($id, $value = TRUE) { + $resource = $this->get($id); + if ($resource !== NULL && !$resource->used()) { + $resource->used($value == TRUE); + return TRUE; + } + return FALSE; + } + + public function get_used() { + $used = array(); + foreach ($this->get() as $resource) { + if ($resource->used()) { + $used[] = $resource; + } + } + return $used; + } + + // XXX Override + public function resource_instance($id, $name = NULL) { + return new CrayonUsedResource($id, $name); + } + + public function get_used_css() { + $used = $this->get_used(); + $css = array(); + foreach ($used as $resource) { + $url = $this->url($resource->id()); + $css[$resource->id()] = $url; + } + return $css; + } +} + +class CrayonUserResourceCollection extends CrayonUsedResourceCollection { + private $user_dir = ''; + private $curr_dir = NULL; + // TODO better to use a base dir and relative + private $relative_directory = NULL; + // TODO move this higher up inheritance + private $extension = ''; + + // XXX Override + public function resource_instance($id, $name = NULL) { + $resource = $this->create_user_resource_instance($id, $name); + $resource->user($this->curr_dir == $this->user_directory()); + return $resource; + } + + public function create_user_resource_instance($id, $name = NULL) { + return new CrayonUserResource($id, $name); + } + + public function user_directory($dir = NULL) { + if ($dir === NULL) { + return $this->user_dir; + } else { + $this->user_dir = CrayonUtil::path_slash($dir); + } + } + + public function relative_directory($relative_directory = NULL) { + if ($relative_directory == NULL) { + return $this->relative_directory; + } + $this->relative_directory = $relative_directory; + } + + public function extension($extension = NULL) { + if ($extension == NULL) { + return $this->extension; + } + $this->extension = $extension; + } + + public function load_resources($dir = NULL) { + $this->curr_dir = $this->directory(); + parent::load_resources($this->curr_dir); + $this->curr_dir = $this->user_directory(); + parent::load_resources($this->curr_dir); + $this->curr_dir = NULL; + } + + public function current_directory() { + return $this->curr_dir; + } + + public function dir_is_user($id, $user = NULL) { + if ($user === NULL) { + if ($this->is_state_loading()) { + // We seem to be loading resources - use current directory + $user = $this->current_directory() == $this->user_directory(); + } else { + $theme = $this->get($id); + if ($theme) { + $user = $theme->user(); + } else { + $user = FALSE; + } + } + } + return $user; + } + + public function dirpath($user = NULL) { + $path = $user ? $this->user_directory() : $this->directory(); + return CrayonUtil::path_slash($path); + } + + public function dirpath_for_id($id, $user = NULL) { + $user = $this->dir_is_user($id, $user); + return $this->dirpath($user) . $id; + } + + public function dirurl($user = NULL) { + $path = $user ? CrayonGlobalSettings::upload_url() : CrayonGlobalSettings::plugin_path(); + return CrayonUtil::path_slash($path . $this->relative_directory()); + } + + // XXX Override + public function path($id, $user = NULL) { + $user = $this->dir_is_user($id, $user); + return $this->dirpath($user) . $this->filename($id, $user); + } + + // XXX Override + public function url($id, $user = NULL) { + $user = $this->dir_is_user($id, $user); + return $this->dirurl($user) . $this->filename($id, $user); + } + + public function filename($id, $user = NULL) { + return "$id.$this->extension"; + } + +} + +class CrayonResource { + private $id = ''; + private $name = ''; + + function __construct($id, $name = NULL) { + $id = $this->clean_id($id); + CrayonUtil::str($this->id, $id); + ( empty($name) ) ? $this->name( self::clean_name($this->id) ) : $this->name($name); + } + + function __tostring() { + return $this->name; + } + + function id() { + return $this->id; + } + + function name($name = NULL) { + if ($name === NULL) { + return $this->name; + } else { + $this->name = $name; + } + } + + function clean_id($id) { + $id = CrayonUtil::space_to_hyphen( strtolower(trim($id)) ); + return preg_replace('#[^\w-]#msi', '', $id); + } + + public static function clean_name($id) { + $id = CrayonUtil::hyphen_to_space( strtolower(trim($id)) ); + return CrayonUtil::ucwords($id); + } + +} + +class CrayonUsedResource extends CrayonResource { + // Keeps track of usage + private $used = FALSE; + + function used($used = NULL) { + if ($used === NULL) { + return $this->used; + } else { + $this->used = ($used ? TRUE : FALSE); + } + } +} + +class CrayonUserResource extends CrayonUsedResource { + // Keeps track of user modifications + private $user = FALSE; + + function user($user = NULL) { + if ($user === NULL) { + return $this->user; + } else { + $this->user = ($user ? TRUE : FALSE); + } + } +} + +class CrayonVersionResource extends CrayonUserResource { + // Adds version + private $version = ''; + + function __construct($id, $name = NULL, $version = NULL) { + parent::__construct($id, $name); + $this->version($version); + } + + function version($version = NULL) { + if ($version === NULL) { + return $this->version; + } else if (is_string($version)) { + $this->version = $version; + } + } +} + +?> \ No newline at end of file diff --git a/crayon_settings.class.php b/crayon_settings.class.php new file mode 100644 index 0000000..9c7acae --- /dev/null +++ b/crayon_settings.class.php @@ -0,0 +1,918 @@ +init(); + } + + function copy() { + $settings = new CrayonSettings(); + foreach ($this->settings as $setting) { + $settings->set($setting); // Overuse of set? + } + return $settings; + } + + // Methods ================================================================ + + private function init() { + global $CRAYON_VERSION; + + crayon_load_plugin_textdomain(); + + self::$cache_array = array(crayon__('Hourly') => 3600, crayon__('Daily') => 86400, + crayon__('Weekly') => 604800, crayon__('Monthly') => 18144000, + crayon__('Immediately') => 1); + + $settings = array( + new CrayonSetting(self::VERSION, $CRAYON_VERSION, NULL, TRUE), + new CrayonSetting(self::THEME, CrayonThemes::DEFAULT_THEME), + new CrayonSetting(self::FONT, CrayonFonts::DEFAULT_FONT), + new CrayonSetting(self::FONT_SIZE_ENABLE, TRUE), + new CrayonSetting(self::FONT_SIZE, 12), + new CrayonSetting(self::LINE_HEIGHT, 15), + new CrayonSetting(self::PREVIEW, TRUE), + new CrayonSetting(self::HEIGHT_SET, FALSE), + new CrayonSetting(self::HEIGHT_MODE, array(crayon__('Max'), crayon__('Min'), crayon__('Static'))), + new CrayonSetting(self::HEIGHT, '500'), + new CrayonSetting(self::HEIGHT_UNIT, array(crayon__('Pixels'), crayon__('Percent'))), + new CrayonSetting(self::WIDTH_SET, FALSE), + new CrayonSetting(self::WIDTH_MODE, array(crayon__('Max'), crayon__('Min'), crayon__('Static'))), + new CrayonSetting(self::WIDTH, '500'), + new CrayonSetting(self::WIDTH_UNIT, array(crayon__('Pixels'), crayon__('Percent'))), + new CrayonSetting(self::TOP_SET, TRUE), + new CrayonSetting(self::TOP_MARGIN, 12), + new CrayonSetting(self::BOTTOM_SET, TRUE), + new CrayonSetting(self::BOTTOM_MARGIN, 12), + new CrayonSetting(self::LEFT_SET, FALSE), + new CrayonSetting(self::LEFT_MARGIN, 12), + new CrayonSetting(self::RIGHT_SET, FALSE), + new CrayonSetting(self::RIGHT_MARGIN, 12), + new CrayonSetting(self::H_ALIGN, array(crayon__('None'), crayon__('Left'), crayon__('Center'), crayon__('Right'))), + new CrayonSetting(self::FLOAT_ENABLE, FALSE), + new CrayonSetting(self::TOOLBAR, array(crayon__('On MouseOver'), crayon__('Always'), crayon__('Never'))), + new CrayonSetting(self::TOOLBAR_OVERLAY, TRUE), + new CrayonSetting(self::TOOLBAR_HIDE, TRUE), + new CrayonSetting(self::TOOLBAR_DELAY, TRUE), + new CrayonSetting(self::COPY, TRUE), + new CrayonSetting(self::POPUP, TRUE), + new CrayonSetting(self::SHOW_LANG, array(crayon__('When Found'), crayon__('Always'), crayon__('Never'))), + new CrayonSetting(self::SHOW_TITLE, TRUE), + new CrayonSetting(self::STRIPED, TRUE), + new CrayonSetting(self::MARKING, TRUE), + new CrayonSetting(self::START_LINE, 1), + new CrayonSetting(self::NUMS, TRUE), + new CrayonSetting(self::NUMS_TOGGLE, TRUE), + new CrayonSetting(self::TRIM_WHITESPACE, TRUE), + new CrayonSetting(self::WHITESPACE_BEFORE, 0), + new CrayonSetting(self::WHITESPACE_AFTER, 0), + new CrayonSetting(self::TRIM_CODE_TAG, TRUE), + new CrayonSetting(self::TAB_CONVERT, FALSE), + new CrayonSetting(self::TAB_SIZE, 4), + new CrayonSetting(self::FALLBACK_LANG, CrayonLangs::DEFAULT_LANG), + new CrayonSetting(self::LOCAL_PATH, ''), + new CrayonSetting(self::SCROLL, FALSE), + new CrayonSetting(self::PLAIN, TRUE), + new CrayonSetting(self::PLAIN_TOGGLE, TRUE), + new CrayonSetting(self::SHOW_PLAIN_DEFAULT, FALSE), + new CrayonSetting(self::SHOW_PLAIN, + array(crayon__('On Double Click'), crayon__('On Single Click'), crayon__('On MouseOver'), crayon__('Disable Mouse Events'))), + new CrayonSetting(self::DISABLE_ANIM, FALSE), + new CrayonSetting(self::TOUCHSCREEN, TRUE), + new CrayonSetting(self::DISABLE_RUNTIME, FALSE), + new CrayonSetting(self::DISABLE_DATE, ''), + new CrayonSetting(self::ERROR_LOG, TRUE), + new CrayonSetting(self::ERROR_LOG_SYS, TRUE), + new CrayonSetting(self::ERROR_MSG_SHOW, TRUE), + new CrayonSetting(self::ERROR_MSG, crayon__('An error has occurred. Please try again later.')), + new CrayonSetting(self::HIDE_HELP, FALSE), + new CrayonSetting(self::CACHE, array_keys(self::$cache_array), 1), + new CrayonSetting(self::EFFICIENT_ENQUEUE, FALSE), + new CrayonSetting(self::CAPTURE_PRE, TRUE), + new CrayonSetting(self::CAPTURE_MINI_TAG, FALSE), + new CrayonSetting(self::MIXED, TRUE), + new CrayonSetting(self::SHOW_MIXED, TRUE), + new CrayonSetting(self::PLAIN_TAG, FALSE), + new CrayonSetting(self::ENQUEUE_THEMES, TRUE), + new CrayonSetting(self::ENQUEUE_FONTS, TRUE), + new CrayonSetting(self::MAIN_QUERY, FALSE), + new CrayonSetting(self::SAFE_ENQUEUE, TRUE), + new CrayonSetting(self::INLINE_TAG, TRUE), + new CrayonSetting(self::INLINE_TAG_CAPTURE, FALSE), + new CrayonSetting(self::CODE_TAG_CAPTURE, FALSE), + new CrayonSetting(self::CODE_TAG_CAPTURE_TYPE, array(crayon__('Inline Tag'), crayon__('Block Tag'))), + new CrayonSetting(self::INLINE_MARGIN, 5), + new CrayonSetting(self::INLINE_WRAP, TRUE), + new CrayonSetting(self::BACKQUOTE, TRUE), + new CrayonSetting(self::COMMENTS, TRUE), + new CrayonSetting(self::DECODE, FALSE), + new CrayonSetting(self::DECODE_ATTRIBUTES, TRUE), +// new CrayonSetting(self::TINYMCE_USED, FALSE), + new CrayonSetting(self::ATTR_SEP, array(':', '_')), + new CrayonSetting(self::EXCERPT_STRIP, FALSE), + new CrayonSetting(self::RANGES, TRUE), + new CrayonSetting(self::TAG_EDITOR_FRONT, FALSE), + new CrayonSetting(self::TAG_EDITOR_SETTINGS, TRUE), + new CrayonSetting(self::TAG_EDITOR_ADD_BUTTON_TEXT, crayon__('Add Code')), + new CrayonSetting(self::TAG_EDITOR_EDIT_BUTTON_TEXT, crayon__('Edit Code')), + new CrayonSetting(self::TAG_EDITOR_QUICKTAG_BUTTON_TEXT, 'crayon'), + new CrayonSetting(self::WRAP_TOGGLE, TRUE), + new CrayonSetting(self::WRAP, FALSE), + new CrayonSetting(self::EXPAND, FALSE), + new CrayonSetting(self::EXPAND_TOGGLE, TRUE), + new CrayonSetting(self::MINIMIZE, FALSE), + new CrayonSetting(self::DELAY_LOAD_JS, FALSE) + ); + + $this->set($settings); + + $nonNegs = array(self::FONT_SIZE, self::LINE_HEIGHT, self::HEIGHT, self::WIDTH, self::START_LINE, self::WHITESPACE_BEFORE, self::WHITESPACE_AFTER, self::TAB_SIZE, self::INLINE_MARGIN); + $intNonNegValid = new CrayonNonNegIntValidator(); + foreach ($nonNegs as $name) { + $this->get($name)->validator($intNonNegValid); + } + } + + // Getter and Setter ====================================================== + + // TODO this needs simplification + function set($name, $value = NULL, $replace = FALSE) { + // Set associative array of settings + if (is_array($name)) { + $keys = array_keys($name); + foreach ($keys as $key) { + if (is_string($key)) { + // Associative value + $this->set($key, $name[$key], $replace); + } else if (is_int($key)) { + $setting = $name[$key]; + $this->set($setting, NULL, $replace); + } + } + } else if (is_string($name) && !empty($name) && $value !== NULL) { + $value = CrayonSettings::validate($name, $value); + if ($replace || !$this->is_setting($name)) { + // Replace/Create + $this->settings[$name] = new CrayonSetting($name, $value); + } else { + // Update + $this->settings[$name]->value($value); + } + } else if (is_object($name) && get_class($name) == CRAYON_SETTING_CLASS) { + $setting = $name; // Semantics + if ($replace || !$this->is_setting($setting->name())) { + // Replace/Create + $this->settings[$setting->name()] = $setting->copy(); + } else { + // Update + if ($setting->is_array()) { + $this->settings[$setting->name()]->index($setting->index()); + } else { + $this->settings[$setting->name()]->value($setting->value()); + } + } + } + } + + function get($name = NULL) { + if ($name === NULL) { + $copy = array(); + foreach ($this->settings as $name => $setting) { + $copy[$name] = $setting->copy(); // Deep copy + } + return $copy; + } else if (is_string($name)) { + if ($this->is_setting($name)) { + return $this->settings[$name]; + } + } + return FALSE; + } + + function val($name = NULL) { + if (($setting = self::get($name)) != FALSE) { + return $setting->value(); + } else { + return NULL; + } + } + + function val_str($name) { + if (($setting = self::get($name)) != FALSE) { + $def = $setting->def(); + $index = $setting->value(); + if (array_key_exists($index, $def)) { + return $def[$index]; + } else { + return NULL; + } + } + } + + function get_array() { + $array = array(); + foreach ($this->settings as $setting) { + $array[$setting->name()] = $setting->value(); + } + return $array; + } + + function is_setting($name) { + return (is_string($name) && array_key_exists($name, $this->settings)); + } + + /* Gets default settings, either as associative array of name=>value or CrayonSetting + objects */ + public static function get_defaults($name = NULL, $objects = TRUE) { + if (self::$default === NULL) { + self::$default = new CrayonSettings(); + } + if ($name === NULL) { + // Get all settings + if ($objects) { + // Return array of objects + return self::$default->get(); + } else { + // Return associative array of name=>value + $settings = self::$default->get(); + $defaults = array(); + foreach ($settings as $setting) { + $defaults[$setting->name()] = $setting->value(); + } + return $defaults; + } + } else { + // Return specific setting + if ($objects) { + return self::$default->get($name); + } else { + return self::$default->get($name)->value(); + } + } + } + + public static function get_defaults_array() { + return self::get_defaults(NULL, FALSE); + } + + // Validation ============================================================= + + /** + * Validates settings coming from an HTML form and also for internal use. + * This is used when saving form an HTML form to the db, and also when reading from the db + * back into the global settings. + * @param string $name + * @param mixed $value + */ + public static function validate($name, $value) { + if (!is_string($name)) { + return ''; + } + + // Type-cast to correct value for known settings + if (($setting = CrayonGlobalSettings::get($name)) != FALSE) { + // Booleans settings that are sent as string are allowed to have "false" == false + if (is_bool($setting->def())) { + if (is_string($value)) { + $value = CrayonUtil::str_to_bool($value); + } + } else { + // Ensure we don't cast integer settings to 0 because $value doesn't have any numbers in it + $value = strval($value); + // Only occurs when saving from the form ($_POST values are strings) + if ($value == '' || ($cleaned = $setting->sanitize($value, FALSE)) == '') { + // The value sent has no integers, change to default + $value = $setting->def(); + } else { + // Cleaned value is int + $value = $cleaned; + } + // Cast all other settings as usual + if (!settype($value, $setting->type())) { + // If we can't cast, then use default value + if ($setting->is_array()) { + $value = 0; // default index + } else { + $value = $setting->def(); + } + } + } + } else { + // If setting not found, remove value + return ''; + } + + switch ($name) { + case CrayonSettings::LOCAL_PATH: + $path = parse_url($value, PHP_URL_PATH); + // Remove all spaces, prefixed and trailing forward slashes + $path = preg_replace('#^/*|/*$|\s*#', '', $path); + // Replace backslashes + $path = preg_replace('#\\\\#', '/', $path); + // Append trailing forward slash + if (!empty($path)) { + $path .= '/'; + } + return $path; + case CrayonSettings::FONT_SIZE: + if ($value < 1) { + $value = 1; + } + break; + case CrayonSettings::LINE_HEIGHT: + $font_size = CrayonGlobalSettings::val(CrayonSettings::FONT_SIZE); + $value = $value >= $font_size ? $value : $font_size; + break; + case CrayonSettings::THEME: + $value = strtolower($value); + // XXX validate settings here + } + + // If no validation occurs, return value + return $value; + } + + // Takes an associative array of "smart settings" and regular settings. Smart settings can be used + // to configure regular settings quickly. + // E.g. 'max_height="20px"' will set 'height="20"', 'height_mode="0", height_unit="0"' + public static function smart_settings($settings) { + if (!is_array($settings)) { + return FALSE; + } + + // If a setting is given, it is automatically enabled + foreach ($settings as $name => $value) { + if (($setting = CrayonGlobalSettings::get($name)) !== FALSE && is_bool($setting->def())) { + $value = CrayonUtil::str_to_bool($value); + } + + // XXX removed height and width, since it wasn't using the global settings for mode if only height was provided + if ($name == 'min-height' || $name == 'max-height' /* || $name == 'height'*/) { + self::smart_hw($name, CrayonSettings::HEIGHT_SET, CrayonSettings::HEIGHT_MODE, CrayonSettings::HEIGHT_UNIT, $settings); + } else if ($name == 'min-width' || $name == 'max-width' /* || $name == 'width'*/) { + self::smart_hw($name, CrayonSettings::WIDTH_SET, CrayonSettings::WIDTH_MODE, CrayonSettings::WIDTH_UNIT, $settings); + } else if ($name == CrayonSettings::FONT_SIZE) { + $settings[CrayonSettings::FONT_SIZE_ENABLE] = TRUE; + } else if ($name == CrayonSettings::TOP_MARGIN) { + $settings[CrayonSettings::TOP_SET] = TRUE; + } else if ($name == CrayonSettings::LEFT_MARGIN) { + $settings[CrayonSettings::LEFT_SET] = TRUE; + } else if ($name == CrayonSettings::BOTTOM_MARGIN) { + $settings[CrayonSettings::BOTTOM_SET] = TRUE; + } else if ($name == CrayonSettings::RIGHT_MARGIN) { + $settings[CrayonSettings::RIGHT_SET] = TRUE; + } else if ($name == CrayonSettings::ERROR_MSG) { + $settings[CrayonSettings::ERROR_MSG_SHOW] = TRUE; + } else if ($name == CrayonSettings::H_ALIGN) { + $settings[CrayonSettings::FLOAT_ENABLE] = TRUE; + $value = CrayonUtil::tlower($value); + $values = array('none' => 0, 'left' => 1, 'center' => 2, 'right' => 3); + if (array_key_exists($value, $values)) { + $settings[CrayonSettings::H_ALIGN] = $values[$value]; + } + } else if ($name == CrayonSettings::SHOW_LANG) { + $value = CrayonUtil::tlower($value); + $values = array('found' => 0, 'always' => 1, 'true' => 1, 'never' => 2, 'false' => 2); + if (array_key_exists($value, $values)) { + $settings[CrayonSettings::SHOW_LANG] = $values[$value]; + } + } else if ($name == CrayonSettings::TOOLBAR) { + if (CrayonUtil::tlower($value) == 'always') { + $settings[CrayonSettings::TOOLBAR] = 1; + } else if (CrayonUtil::str_to_bool($value) === FALSE) { + $settings[CrayonSettings::TOOLBAR] = 2; + } + } + } + + return $settings; + } + + // Used for height and width smart settings, I couldn't bear to copy paste code twice... + private static function smart_hw($name, $set, $mode, $unit, &$settings) { + if (!is_string($name) || !is_string($set) || !is_string($mode) || !is_string($unit) || !is_array($settings)) { + return; + } + $settings[$set] = TRUE; + if (strpos($name, 'max-') !== FALSE) { + $settings[$mode] = 0; + } else if (strpos($name, 'min-') !== FALSE) { + $settings[$mode] = 1; + } else { + $settings[$mode] = 2; + } + preg_match('#(\d+)\s*([^\s]*)#', $settings[$name], $match); + if (count($match) == 3) { + $name = str_replace(array('max-', 'min-'), '', $name); + $settings[$name] = $match[1]; + switch (strtolower($match[2])) { + case 'px': + $settings[$unit] = 0; + break; + case '%': + $settings[$unit] = 1; + break; + } + } + } +} + +/** + * Stores global/static copy of CrayonSettings loaded from db. + * These settings can be overriden by individual Crayons. + * Also manages global site settings and paths. + */ +class CrayonGlobalSettings { + // The global settings stored as a CrayonSettings object. + private static $global = NULL; + /* These are used to load local files reliably and prevent scripts like PHP from executing + when attempting to load their code. */ + // The URL of the site (eg. http://localhost/example/) + private static $site_http = ''; + // The absolute root directory of the site (eg. /User/example/) + private static $site_path = ''; + // The absolute root directory of the plugins (eg. /User/example/plugins) + private static $plugin_path = ''; + private static $upload_path = ''; + private static $upload_url = ''; + private static $mkdir = NULL; + + private function __construct() { + } + + private static function init() { + if (self::$global === NULL) { + self::$global = new CrayonSettings(); + } + } + + public static function get($name = NULL) { + self::init(); + return self::$global->get($name); + } + + public static function get_array() { + self::init(); + return self::$global->get_array(); + } + + public static function get_obj() { + self::init(); + return self::$global->copy(); + } + + public static function val($name = NULL) { + self::init(); + return self::$global->val($name); + } + + public static function val_str($name = NULL) { + self::init(); + return self::$global->val_str($name); + } + + public static function has_changed($input, $setting, $value) { + return $input == $setting && $value != CrayonGlobalSettings::val($setting); + } + + public static function set($name, $value = NULL, $replace = FALSE) { + self::init(); + self::$global->set($name, $value, $replace); + } + + public static function site_url($site_http = NULL) { + if ($site_http === NULL) { + return self::$site_http; + } else { + self::$site_http = CrayonUtil::url_slash($site_http); + } + } + + public static function site_path($site_path = NULL) { + if ($site_path === NULL) { + return self::$site_path; + } else { + self::$site_path = CrayonUtil::path_slash($site_path); + } + } + + public static function plugin_path($plugin_path = NULL) { + if ($plugin_path === NULL) { + return self::$plugin_path; + } else { + self::$plugin_path = CrayonUtil::path_slash($plugin_path); + } + } + + public static function upload_path($upload_path = NULL) { + if ($upload_path === NULL) { + return self::$upload_path; + } else { + self::$upload_path = CrayonUtil::path_slash($upload_path); + } + } + + public static function upload_url($upload_url = NULL) { + if ($upload_url === NULL) { + return self::$upload_url; + } else { + self::$upload_url = CrayonUtil::url_slash($upload_url); + } + } + + public static function set_mkdir($mkdir = NULL) { + if ($mkdir === NULL) { + return self::$mkdir; + } else { + self::$mkdir = $mkdir; + } + } + + public static function mkdir($dir = NULL) { + if (self::$mkdir) { + call_user_func(self::$mkdir, $dir); + } else { + @mkdir($dir, 0777, TRUE); + } + } +} + + +$INT = new CrayonValidator('#\d+#'); + +/** + * Validation class. + */ +class CrayonValidator { + private $pattern = '#*#msi'; + + public function __construct($pattern) { + $this->pattern($pattern); + } + + public function pattern($pattern) { + if ($pattern === NULL) { + return $pattern; + } else { + $this->pattern = $pattern; + } + } + + public function validate($str) { + return preg_match($this->pattern, $str) !== FALSE; + } + + public function sanitize($str) { + preg_match_all($this->pattern, $str, $matches); + $result = ''; + foreach ($matches as $match) { + $result .= $match[0]; + } + return $result; + } +} + +class CrayonNonNegIntValidator extends CrayonValidator { + public function __construct() { + parent::__construct('#\d+#'); + } +} + +class CrayonIntValidator extends CrayonValidator { + public function __construct() { + parent::__construct('#-?\d+#'); + } +} + +/** + * Individual setting. + * Can store boolean, string, dropdown (with array of strings), etc. + */ +class CrayonSetting { + private $name = ''; + /* The type of variables that can be set as the value. + * For dropdown settings, value is int, even though value() will return a string. */ + private $type = NULL; + private $default = NULL; // stores string array for dropdown settings + + private $value = NULL; // stores index int for dropdown settings + + private $is_array = FALSE; // only TRUE for dropdown settings + private $locked = FALSE; + + private $validator = NULL; + + + public function __construct($name, $default = '', $value = NULL, $locked = NULL) { + $this->name($name); + if ($default !== NULL) { + $this->def($default); // Perform first to set type + } + if ($value !== NULL) { + $this->value($value); + } + if ($locked !== NULL) { + $this->locked($locked); + } + } + + function __tostring() { + return $this->name; + } + + function copy() { + return new CrayonSetting($this->name, $this->default, $this->value, $this->locked); + } + + function name($name = NULL) { + if (!CrayonUtil::str($this->name, $name)) { + return $this->name; + } + } + + function type() { + return $this->type; + } + + function is_array() { + return $this->is_array; + } + + function locked($locked = NULL) { + if ($locked === NULL) { + return $this->locked; + } else { + $this->locked = ($locked == TRUE); + } + } + + /** + * Sets/gets value; + * Value is index (int) in default value (array) for dropdown settings. + * value($value) is alias for index($index) if dropdown setting. + * value() returns string value at current index for dropdown settings. + * @param $value + */ + function value($value = NULL) { + if ($value === NULL) { + /*if ($this->is_array) { + return $this->default[$this->value]; // value at index + } else */ + if ($this->value !== NULL) { + return $this->value; + } else { + if ($this->is_array) { + return 0; + } else { + return $this->default; + } + } + } else if ($this->locked === FALSE) { + if ($this->is_array) { + $this->index($value); // $value is index + } else { + settype($value, $this->type); // Type cast + $this->value = $value; + } + } + } + + function array_value() { + if ($this->is_array) { + return NULL; + } + return $this->default[$this->value]; + } + + /** + * Sets/gets default value. + * For dropdown settings, default value is array of all possible value strings. + * @param $default + */ + function def($default = NULL) { + // Only allow default to be set once + + if ($this->type === NULL && $default !== NULL) { + // For dropdown settings + + if (is_array($default)) { // The only time we don't use $this->is_array + + // If empty, set to blank array + + if (empty($default)) { + $default = array(''); + } else { + // Ensure all values are unique strings + + $default = CrayonUtil::array_unique_str($default); + } + $this->value = 0; // initial index + + $this->is_array = TRUE; + $this->type = gettype(0); // Type is int (index) + + } else { + $this->is_array = FALSE; + $this->type = gettype($default); + if (is_int($default)) { + $this->validator(new CrayonIntValidator()); + } + } + $this->default = $default; + } else { + return $this->default; + } + } + + /** + * Sets/gets index. + * @param int|string $index + * @return FALSE if not dropdown setting + */ + function index($index = NULL) { + if (!$this->is_array) { + return FALSE; + } else if ($index === NULL) { + return $this->value; // return current index + } else { + if (!is_int($index)) { + // Ensure $value is int for index + $index = intval($index); + } + // Validate index + if ($index < 0 || $index > count($this->default) - 1) { + $index = 0; + } + $this->value = $index; + } + } + + /** + * Finds the index of a string in an array setting + */ + function find_index($str) { + if (!$this->is_array || is_string($str)) { + return FALSE; + } + for ($i = 0; $i < count($this->default); $i++) { + if ($this->default[$i] == $str) { + return $i; + } + } + return FALSE; + } + + function validator($validator) { + if ($validator === NULL) { + return $this->validator; + } else { + $this->validator = $validator; + } + } + + function sanitize($str) { + if ($this->validator != NULL) { + return $this->validator->sanitize($str); + } else { + return $str; + } + } + +} + +?> \ No newline at end of file diff --git a/crayon_settings_wp.class.php b/crayon_settings_wp.class.php new file mode 100644 index 0000000..640732f --- /dev/null +++ b/crayon_settings_wp.class.php @@ -0,0 +1,1273 @@ += '3.3') { + add_action("load-$admin_page", 'CrayonSettingsWP::help_screen'); + } else { + add_filter('contextual_help', 'CrayonSettingsWP::cont_help', 10, 3); + } + } + + public static function admin_styles() { + global $CRAYON_VERSION; + if (CRAYON_MINIFY) { + wp_enqueue_style('crayon', plugins_url(CRAYON_STYLE_MIN, __FILE__), array('editor-buttons'), $CRAYON_VERSION); + } else { + wp_enqueue_style('crayon', plugins_url(CRAYON_STYLE, __FILE__), array(), $CRAYON_VERSION); + wp_enqueue_style('crayon_global', plugins_url(CRAYON_STYLE_GLOBAL, __FILE__), array(), $CRAYON_VERSION); + wp_enqueue_style('crayon_admin', plugins_url(CRAYON_STYLE_ADMIN, __FILE__), array('editor-buttons'), $CRAYON_VERSION); + } + } + + public static function admin_scripts() { + global $CRAYON_VERSION; + + if (CRAYON_MINIFY) { + CrayonWP::enqueue_resources(); + } else { + wp_enqueue_script('crayon_util_js', plugins_url(CRAYON_JS_UTIL, __FILE__), array('jquery'), $CRAYON_VERSION); + self::other_scripts(); + } + + self::init_js_settings(); + + if (is_admin()) { + wp_enqueue_script('crayon_admin_js', plugins_url(CRAYON_JS_ADMIN, __FILE__), array('jquery', 'crayon_js', 'wpdialogs'), $CRAYON_VERSION); + self::init_admin_js_settings(); + } + } + + public static function other_scripts() { + global $CRAYON_VERSION; + self::load_settings(TRUE); + $deps = array('jquery', 'crayon_util_js'); + if (CrayonGlobalSettings::val(CrayonSettings::POPUP) || is_admin()) { + // TODO include anyway and minify + wp_enqueue_script('crayon_jquery_popup', plugins_url(CRAYON_JQUERY_POPUP, __FILE__), array('jquery'), $CRAYON_VERSION); + $deps[] = 'crayon_jquery_popup'; + } + wp_enqueue_script('crayon_js', plugins_url(CRAYON_JS, __FILE__), $deps, $CRAYON_VERSION); + } + + public static function init_js_settings() { + // This stores JS variables used in AJAX calls and in the JS files + global $CRAYON_VERSION; + self::load_settings(TRUE); + if (!self::$js_settings) { + self::$js_settings = array( + 'version' => $CRAYON_VERSION, + 'is_admin' => intval(is_admin()), + 'ajaxurl' => admin_url('admin-ajax.php'), + 'prefix' => CrayonSettings::PREFIX, + 'setting' => CrayonSettings::SETTING, + 'selected' => CrayonSettings::SETTING_SELECTED, + 'changed' => CrayonSettings::SETTING_CHANGED, + 'special' => CrayonSettings::SETTING_SPECIAL, + 'orig_value' => CrayonSettings::SETTING_ORIG_VALUE, + 'debug' => CRAYON_DEBUG + ); + } + if (!self::$js_strings) { + self::$js_strings = array( + 'copy' => crayon__('Press %s to Copy, %s to Paste'), + 'minimize' => crayon__('Click To Expand Code') + ); + } + if (CRAYON_MINIFY) { + wp_localize_script('crayon_js', 'CrayonSyntaxSettings', self::$js_settings); + wp_localize_script('crayon_js', 'CrayonSyntaxStrings', self::$js_strings); + } else { + wp_localize_script('crayon_util_js', 'CrayonSyntaxSettings', self::$js_settings); + wp_localize_script('crayon_util_js', 'CrayonSyntaxStrings', self::$js_strings); + } + } + + public static function init_admin_js_settings() { + if (!self::$admin_js_settings) { + // We need to load themes at this stage + CrayonSettingsWP::load_settings(); + $themes_ = CrayonResources::themes()->get(); + $stockThemes = array(); + $userThemes = array(); + foreach ($themes_ as $theme) { + $id = $theme->id(); + $name = $theme->name(); + if ($theme->user()) { + $userThemes[$id] = $name; + } else { + $stockThemes[$id] = $name; + } + } + self::$admin_js_settings = array( + 'themes' => array_merge($stockThemes, $userThemes), + 'stockThemes' => $stockThemes, + 'userThemes' => $userThemes, + 'defaultTheme' => CrayonThemes::DEFAULT_THEME, + 'themesURL' => CrayonResources::themes()->dirurl(false), + 'userThemesURL' => CrayonResources::themes()->dirurl(true), + 'sampleCode' => self::SAMPLE_CODE, + 'dialogFunction' => 'wpdialog' + ); + wp_localize_script('crayon_admin_js', 'CrayonAdminSettings', self::$admin_js_settings); + } + if (!self::$admin_js_strings) { + self::$admin_js_strings = array( + 'prompt' => crayon__("Prompt"), + 'value' => crayon__("Value"), + 'alert' => crayon__("Alert"), + 'no' => crayon__("No"), + 'yes' => crayon__("Yes"), + 'confirm' => crayon__("Confirm"), + 'changeCode' => crayon__("Change Code") + ); + wp_localize_script('crayon_admin_js', 'CrayonAdminStrings', self::$admin_js_strings); + } + } + + public static function settings() { + if (!current_user_can('manage_options')) { + wp_die(crayon__('You do not have sufficient permissions to access this page.')); + } + ?> + + + +
+ +
+
+
+

+ Crayon Syntax Highlighter + +

+ +
+ + + + +

+ + +

+
+
+ +
+ + load(); + CrayonResources::themes()->load(); + + // Ensure all missing settings in db are replaced by default values + $changed = FALSE; + foreach (CrayonSettings::get_defaults_array() as $name => $value) { + // Add missing settings + if (!array_key_exists($name, self::$options)) { + self::$options[$name] = $value; + $changed = TRUE; + } + } + // A setting was missing, update options + if ($changed) { + update_option(self::OPTIONS, self::$options); + } + + self::$is_fully_loaded = TRUE; + } + } + + public static function get_settings() { + return get_option(self::OPTIONS); + } + + // Saves settings from CrayonGlobalSettings, or provided array, to the db + public static function save_settings($settings = NULL) { + if ($settings === NULL) { + $settings = CrayonGlobalSettings::get_array(); + } + update_option(self::OPTIONS, $settings); + } + + // Crayon posts + + /** + * This loads the posts marked as containing Crayons + */ + public static function load_posts() { + if (self::$crayon_posts === NULL) { + // Load from db + if (!(self::$crayon_posts = get_option(self::POSTS))) { + // Posts don't exist! Scan for them. This will fill self::$crayon_posts + self::$crayon_posts = CrayonWP::scan_posts(); + update_option(self::POSTS, self::$crayon_posts); + } + } + return self::$crayon_posts; + } + + /** + * This looks through all posts and marks those which contain Crayons + */ +// public static function scan_and_save_posts() { +// self::save_posts(CrayonWP::scan_posts(TRUE, TRUE)); +// } + + /** + * Saves the marked posts to the db + */ + public static function save_posts($posts = NULL) { + if ($posts === NULL) { + $posts = self::$crayon_posts; + } + update_option(self::POSTS, $posts); + self::load_posts(); + } + + /** + * Adds a post as containing a Crayon + */ + public static function add_post($id, $save = TRUE) { + self::load_posts(); + if (!in_array($id, self::$crayon_posts)) { + self::$crayon_posts[] = $id; + } + if ($save) { + self::save_posts(); + } + } + + /** + * Removes a post as not containing a Crayon + */ + public static function remove_post($id, $save = TRUE) { + self::load_posts(); + $key = array_search($id, self::$crayon_posts); + if ($key === false) { + return; + } + unset(self::$crayon_posts[$key]); + if ($save) { + self::save_posts(); + } + } + + public static function remove_posts() { + self::$crayon_posts = array(); + self::save_posts(); + } + + // Crayon legacy posts + + /** + * This loads the posts marked as containing Crayons + */ + public static function load_legacy_posts($force = FALSE) { + if (self::$crayon_legacy_posts === NULL || $force) { + // Load from db + if (!(self::$crayon_legacy_posts = get_option(self::LEGACY_POSTS))) { + // Posts don't exist! Scan for them. This will fill self::$crayon_legacy_posts + self::$crayon_legacy_posts = CrayonWP::scan_legacy_posts(); + update_option(self::LEGACY_POSTS, self::$crayon_legacy_posts); + } + } + return self::$crayon_legacy_posts; + } + + /** + * This looks through all posts and marks those which contain Crayons + */ +// public static function scan_and_save_posts() { +// self::save_posts(CrayonWP::scan_posts(TRUE, TRUE)); +// } + + /** + * Saves the marked posts to the db + */ + public static function save_legacy_posts($posts = NULL) { + if ($posts === NULL) { + $posts = self::$crayon_legacy_posts; + } + update_option(self::LEGACY_POSTS, $posts); + self::load_legacy_posts(); + } + + /** + * Adds a post as containing a Crayon + */ + public static function add_legacy_post($id, $save = TRUE) { + self::load_legacy_posts(); + if (!in_array($id, self::$crayon_legacy_posts)) { + self::$crayon_legacy_posts[] = $id; + } + if ($save) { + self::save_legacy_posts(); + } + } + + /** + * Removes a post as not containing a Crayon + */ + public static function remove_legacy_post($id, $save = TRUE) { + self::load_legacy_posts(); + $key = array_search($id, self::$crayon_legacy_posts); + if ($key === false) { + return; + } + unset(self::$crayon_legacy_posts[$key]); + if ($save) { + self::save_legacy_posts(); + } + } + + public static function remove_legacy_posts() { + self::$crayon_legacy_posts = array(); + self::save_legacy_posts(); + } + + // Cache + + public static function add_cache($name) { + self::load_cache(); + if (!in_array($name, self::$cache)) { + self::$cache[] = $name; + } + self::save_cache(); + } + + public static function remove_cache($name) { + self::load_cache(); + $key = array_search($name, self::$cache); + if ($key === false) { + return; + } + unset(self::$cache[$key]); + self::save_cache(); + } + + public static function clear_cache() { + self::load_cache(); + foreach (self::$cache as $name) { + delete_transient($name); + } + self::$cache = array(); + self::save_cache(); + } + + public static function load_cache() { + // Load cache from db + if (!(self::$cache = get_option(self::CACHE))) { + self::$cache = array(); + update_option(self::CACHE, self::$cache); + } + } + + public static function save_cache() { + update_option(self::CACHE, self::$cache); + self::load_cache(); + } + + // Paths + + public static function admin_init() { + // Load default settings if they don't exist + self::load_settings(); + + // General + // Some of these will the $editor arguments, if TRUE it will alter for use in the Tag Editor + self::add_section(self::GENERAL, crayon__('General')); + self::add_field(self::GENERAL, crayon__('Theme'), 'theme'); + self::add_field(self::GENERAL, crayon__('Font'), 'font'); + self::add_field(self::GENERAL, crayon__('Metrics'), 'metrics'); + self::add_field(self::GENERAL, crayon__('Toolbar'), 'toolbar'); + self::add_field(self::GENERAL, crayon__('Lines'), 'lines'); + self::add_field(self::GENERAL, crayon__('Code'), 'code'); + self::add_field(self::GENERAL, crayon__('Tags'), 'tags'); + self::add_field(self::GENERAL, crayon__('Languages'), 'langs'); + self::add_field(self::GENERAL, crayon__('Files'), 'files'); + self::add_field(self::GENERAL, crayon__('Posts'), 'posts'); + self::add_field(self::GENERAL, crayon__('Tag Editor'), 'tag_editor'); + self::add_field(self::GENERAL, crayon__('Misc'), 'misc'); + + // Debug + self::add_section(self::DEBUG, crayon__('Debug')); + self::add_field(self::DEBUG, crayon__('Errors'), 'errors'); + self::add_field(self::DEBUG, crayon__('Log'), 'log'); + // ABOUT + + self::add_section(self::ABOUT, crayon__('About')); + $image = ''; + self::add_field(self::ABOUT, $image, 'info'); + } + + // Wrapper functions + + private static function add_section($name, $title, $callback = NULL) { + $callback = (empty($callback) ? 'blank' : $callback); + add_settings_section($name, $title, 'CrayonSettingsWP::' . $callback, self::SETTINGS); + } + + private static function add_field($section, $title, $callback, $args = array()) { + $unique = preg_replace('#\\s#', '_', strtolower($title)); + add_settings_field($unique, $title, 'CrayonSettingsWP::' . $callback, self::SETTINGS, $section, $args); + } + + // Validates all the settings passed from the form in $inputs + + public static function settings_validate($inputs) { + + // Load current settings from db + self::load_settings(TRUE); + + global $CRAYON_EMAIL; + // When reset button is pressed, remove settings so default loads next time + if (array_key_exists('reset', $inputs)) { + self::clear_cache(); + return array(); + } + // Convert old tags + if (array_key_exists('convert', $inputs)) { + $encode = array_key_exists('convert_encode', $inputs); + CrayonWP::convert_tags($encode); + } + // Refresh internal tag management + if (array_key_exists('refresh_tags', $inputs)) { + CrayonWP::refresh_posts(); + } + // Clear the log if needed + if (array_key_exists(self::LOG_CLEAR, $_POST)) { + CrayonLog::clear(); + } + // Send to admin + if (array_key_exists(self::LOG_EMAIL_ADMIN, $_POST)) { + CrayonLog::email(get_bloginfo('admin_email')); + } + // Send to developer + if (array_key_exists(self::LOG_EMAIL_DEV, $_POST)) { + CrayonLog::email($CRAYON_EMAIL, get_bloginfo('admin_email')); + } + + // Clear the cache + if (array_key_exists(self::CACHE_CLEAR, $_POST)) { + self::clear_cache(); + } + + // If settings don't exist in input, set them to default + $global_settings = CrayonSettings::get_defaults(); + + $ignored = array(CrayonSettings::HIDE_HELP); + + foreach ($global_settings as $setting) { + // XXX Ignore some settings + if (in_array($setting->name(), $ignored)) { + $inputs[$setting->name()] = CrayonGlobalSettings::val($setting->name()); + continue; + } + + // If boolean setting is not in input, then it is set to FALSE in the form + if (!array_key_exists($setting->name(), $inputs)) { + // For booleans, set to FALSE (unchecked boxes are not sent as POST) + if (is_bool($setting->def())) { + $inputs[$setting->name()] = FALSE; + } else { + /* For array settings, set the input as the value, which by default is the + default index */ + if (is_array($setting->def())) { + $inputs[$setting->name()] = $setting->value(); + } else { + $inputs[$setting->name()] = $setting->def(); + } + } + } + } + + $refresh = array( + // These should trigger a refresh of which posts contain crayons, since they affect capturing + CrayonSettings::INLINE_TAG => TRUE, + CrayonSettings::INLINE_TAG_CAPTURE => TRUE, + CrayonSettings::CODE_TAG_CAPTURE => TRUE, + CrayonSettings::BACKQUOTE => TRUE, + CrayonSettings::CAPTURE_PRE => TRUE, + CrayonSettings::CAPTURE_MINI_TAG => TRUE, + CrayonSettings::PLAIN_TAG => TRUE + ); + + // Validate inputs + foreach ($inputs as $input => $value) { + // Convert all array setting values to ints + $inputs[$input] = $value = CrayonSettings::validate($input, $value); + // Clear cache when changed + if (CrayonGlobalSettings::has_changed($input, CrayonSettings::CACHE, $value)) { + self::clear_cache(); + } + if (isset($refresh[$input])) { + if (CrayonGlobalSettings::has_changed($input, $input, $value)) { + // Needs to take place, in case it refresh depends on changed value + CrayonGlobalSettings::set($input, $value); + CrayonWP::refresh_posts(); + } + } + } + + return $inputs; + } + + // Section callback functions + + public static function blank() { + } // Used for required callbacks with blank content + + // Input Drawing ========================================================== + + private static function input($args) { + $id = ''; + $size = 40; + $margin = FALSE; + $preview = 1; + $break = FALSE; + $type = 'text'; + extract($args); + + echo '', ($break ? CRAYON_BR : ''); + } + + private static function checkbox($args, $line_break = TRUE, $preview = TRUE) { + if (empty($args) || !is_array($args) || count($args) != 2) { + return; + } + $id = $args[0]; + $text = $args[1]; + $checked = (!array_key_exists($id, self::$options)) ? FALSE : self::$options[$id] == TRUE; + $checked_str = $checked ? ' checked="checked"' : ''; + echo ' ', '', ($line_break ? CRAYON_BR : ''); + } + + // Draws a dropdown by loading the default value (an array) from a setting + private static function dropdown($id, $line_break = TRUE, $preview = TRUE, $echo = TRUE, $resources = NULL, $selected = NULL) { + if (!array_key_exists($id, self::$options)) { + return; + } + $resources = $resources != NULL ? $resources : CrayonGlobalSettings::get($id)->def(); + + $return = '' . ($line_break ? CRAYON_BR : ''); + if ($echo) { + echo $return; + } else { + return $return; + } + } + + private static function button($args = array()) { + extract($args); + CrayonUtil::set_var($id, ''); + CrayonUtil::set_var($class, ''); + CrayonUtil::set_var($onclick, ''); + CrayonUtil::set_var($title, ''); + return '' . $title . ''; + } + + private static function info_span($name, $text) { + echo '', $text, ''; + } + + private static function span($text) { + echo '', $text, ''; + } + + // General Fields ========================================================= + public static function help() { + global $CRAYON_WEBSITE, $CRAYON_TWITTER, $CRAYON_GIT, $CRAYON_PLUGIN_WP, $CRAYON_DONATE; + if (CrayonGlobalSettings::val(CrayonSettings::HIDE_HELP)) { + return; + } + echo '
+

Howdy, coder! Thanks for using Crayon. Useful Links: Documentation, GitHub, Plugin Page, Twitter. Crayon has always been free. If you value my work please consider a small donation to show your appreciation. Thanks! X

+ '; + } + + public static function help_screen() { + $screen = get_current_screen(); + + if ($screen->id != self::$admin_page) { + return; + } + } + + public static function metrics() { + echo '
'; + self::checkbox(array(CrayonSettings::HEIGHT_SET, '' . crayon__('Height') . ' '), FALSE); + self::dropdown(CrayonSettings::HEIGHT_MODE, FALSE); + echo ' '; + self::input(array('id' => CrayonSettings::HEIGHT, 'size' => 8)); + echo ' '; + self::dropdown(CrayonSettings::HEIGHT_UNIT); + self::checkbox(array(CrayonSettings::WIDTH_SET, '' . crayon__('Width') . ' '), FALSE); + self::dropdown(CrayonSettings::WIDTH_MODE, FALSE); + echo ' '; + self::input(array('id' => CrayonSettings::WIDTH, 'size' => 8)); + echo ' '; + self::dropdown(CrayonSettings::WIDTH_UNIT); + $text = array(crayon__('Top Margin') => array(CrayonSettings::TOP_SET, CrayonSettings::TOP_MARGIN), + crayon__('Bottom Margin') => array(CrayonSettings::BOTTOM_SET, CrayonSettings::BOTTOM_MARGIN), + crayon__('Left Margin') => array(CrayonSettings::LEFT_SET, CrayonSettings::LEFT_MARGIN), + crayon__('Right Margin') => array(CrayonSettings::RIGHT_SET, CrayonSettings::RIGHT_MARGIN)); + foreach ($text as $p => $s) { + $set = $s[0]; + $margin = $s[1]; + $preview = ($p == crayon__('Left Margin') || $p == crayon__('Right Margin')); + self::checkbox(array($set, '' . $p . ''), FALSE, $preview); + echo ' '; + self::input(array('id' => $margin, 'size' => 8, 'preview' => FALSE)); + echo '', crayon__('Pixels'), '', CRAYON_BR; + } + echo '' . crayon__('Horizontal Alignment') . ' '; + self::dropdown(CrayonSettings::H_ALIGN); + echo '
'; + self::checkbox(array(CrayonSettings::FLOAT_ENABLE, crayon__('Allow floating elements to surround Crayon')), FALSE, FALSE); + echo '
'; + echo '' . crayon__('Inline Margin') . ' '; + self::input(array('id' => CrayonSettings::INLINE_MARGIN, 'size' => 2)); + echo '', crayon__('Pixels'), ''; + echo '
'; + } + + public static function toolbar() { + echo '
'; + self::span(crayon__('Display the Toolbar') . ' '); + self::dropdown(CrayonSettings::TOOLBAR); + echo '
'; + self::checkbox(array(CrayonSettings::TOOLBAR_OVERLAY, crayon__('Overlay the toolbar on code rather than push it down when possible'))); + self::checkbox(array(CrayonSettings::TOOLBAR_HIDE, crayon__('Toggle the toolbar on single click when it is overlayed'))); + self::checkbox(array(CrayonSettings::TOOLBAR_DELAY, crayon__('Delay hiding the toolbar on MouseOut'))); + echo '
'; + self::checkbox(array(CrayonSettings::SHOW_TITLE, crayon__('Display the title when provided'))); + self::span(crayon__('Display the language') . ' '); + self::dropdown(CrayonSettings::SHOW_LANG); + echo '
'; + } + + public static function lines() { + echo '
'; + self::checkbox(array(CrayonSettings::STRIPED, crayon__('Display striped code lines'))); + self::checkbox(array(CrayonSettings::MARKING, crayon__('Enable line marking for important lines'))); + self::checkbox(array(CrayonSettings::RANGES, crayon__('Enable line ranges for showing only parts of code'))); + self::checkbox(array(CrayonSettings::NUMS, crayon__('Display line numbers by default'))); + self::checkbox(array(CrayonSettings::NUMS_TOGGLE, crayon__('Enable line number toggling'))); + self::checkbox(array(CrayonSettings::WRAP, crayon__('Wrap lines by default'))); + self::checkbox(array(CrayonSettings::WRAP_TOGGLE, crayon__('Enable line wrap toggling'))); + self::span(crayon__('Start line numbers from') . ' '); + self::input(array('id' => CrayonSettings::START_LINE, 'size' => 2, 'break' => TRUE)); + echo '
'; + } + + public static function langs() { + echo ''; + // Specialised dropdown for languages + if (array_key_exists(CrayonSettings::FALLBACK_LANG, self::$options)) { + if (($langs = CrayonParser::parse_all()) != FALSE) { + $langs = CrayonLangs::sort_by_name($langs); + self::span(crayon__('When no language is provided, use the fallback') . ': '); + self::dropdown(CrayonSettings::FALLBACK_LANG, FALSE, TRUE, TRUE, $langs); + // Information about parsing + $parsed = CrayonResources::langs()->is_parsed(); + $count = count($langs); + echo '', CRAYON_BR, ($parsed ? '' : ''), + sprintf(crayon_n('%d language has been detected.', '%d languages have been detected.', $count), $count), ' ', + $parsed ? crayon__('Parsing was successful') : crayon__('Parsing was unsuccessful'), + ($parsed ? '. ' : ''); + // Check if fallback from db is loaded + $db_fallback = self::$options[CrayonSettings::FALLBACK_LANG]; // Fallback name from db + + if (!CrayonResources::langs()->is_loaded($db_fallback) || !CrayonResources::langs()->exists($db_fallback)) { + echo '
', sprintf(crayon__('The selected language with id %s could not be loaded'), '' . $db_fallback . ''), '. '; + } + // Language parsing info + echo CRAYON_BR, '
' . self::button(array('id' => 'show-langs', 'title' => crayon__('Show Languages'))) . '
'; + } else { + echo crayon__('No languages could be parsed.'); + } + } + } + + public static function show_langs() { + CrayonSettingsWP::load_settings(); + require_once(CRAYON_PARSER_PHP); + if (($langs = CrayonParser::parse_all()) != FALSE) { + $langs = CrayonLangs::sort_by_name($langs); + echo '', + ''; + $keys = array_values($langs); + for ($i = 0; $i < count($langs); $i++) { + $lang = $keys[$i]; + $tr = ($i == count($langs) - 1) ? 'crayon-table-last' : ''; + echo '', + '', + '', + '', + '', + '', + '', + ''; + } + echo '
', crayon__('ID'), '', crayon__('Name'), '', crayon__('Version'), '', crayon__('File Extensions'), '', crayon__('Aliases'), '', crayon__('State'), '
', $lang->id(), '', $lang->name(), '', $lang->version(), '', implode(', ', $lang->ext()), '', implode(', ', $lang->alias()), '', + $lang->state_info(), '

' . crayon__("Languages that have the same extension as their name don't need to explicitly map extensions."); + } else { + echo crayon__('No languages could be found.'); + } + exit(); + } + + public static function posts() { + echo ''; + echo self::button(array('id' => 'show-posts', 'title' => crayon__('Show Crayon Posts'))); + echo ' '; + echo self::help_button('http://aramk.com/blog/2012/09/26/internal-post-management-crayon/'); + echo '
'; + } + + public static function post_cmp($a, $b) { + $a = $a->post_modified; + $b = $b->post_modified; + if ($a == $b) { + return 0; + } else { + return $a < $b ? 1 : -1; + } + } + + public static function show_posts() { + CrayonSettingsWP::load_settings(); + $postIDs = self::load_posts(); + $legacy_posts = self::load_legacy_posts(); + // Avoids O(n^2) by using a hash map, tradeoff in using strval + $legacy_map = array(); + foreach ($legacy_posts as $legacyID) { + $legacy_map[strval($legacyID)] = TRUE; + } + + echo '', + ''; + + $posts = array(); + for ($i = 0; $i < count($postIDs); $i++) { + $posts[$i] = get_post($postIDs[$i]); + } + + usort($posts, 'CrayonSettingsWP::post_cmp'); + + for ($i = 0; $i < count($posts); $i++) { + $post = $posts[$i]; + $postID = $post->ID; + $title = $post->post_title; + $title = !empty($title) ? $title : 'N/A'; + $tr = ($i == count($posts) - 1) ? 'crayon-table-last' : ''; + echo '', + '', + '', + '', + '', + '', + ''; + } + + echo '
', crayon__('ID'), '', crayon__('Title'), '', crayon__('Posted'), '', crayon__('Modifed'), '', crayon__('Contains Legacy Tags?'), '
', $postID, '', $title, '', $post->post_date, '', $post->post_modified, '', isset($legacy_map[strval($postID)]) ? '' . crayon__('Yes') . '' : crayon__('No'), '
'; + exit(); + } + + public static function show_preview() { + echo '
'; + + self::load_settings(); // Run first to ensure global settings loaded + + $crayon = CrayonWP::instance(); + + // Settings to prevent from validating + $preview_settings = array(self::SAMPLE_CODE); + + // Load settings from GET and validate + foreach ($_POST as $key => $value) { + // echo $key, ' ', $value , '
'; + $value = stripslashes($value); + if (!in_array($key, $preview_settings)) { + $_POST[$key] = CrayonSettings::validate($key, $value); + } else { + $_POST[$key] = $value; + } + } + $crayon->settings($_POST); + if (!isset($crayon_preview_dont_override_get) || !$crayon_preview_dont_override_get) { + $settings = array(CrayonSettings::TOP_SET => TRUE, CrayonSettings::TOP_MARGIN => 10, + CrayonSettings::BOTTOM_SET => FALSE, CrayonSettings::BOTTOM_MARGIN => 0); + $crayon->settings($settings); + } + + // Print the theme CSS + $theme_id = $crayon->setting_val(CrayonSettings::THEME); + if ($theme_id != NULL) { + echo CrayonResources::themes()->get_css($theme_id, date('U')); + } + + $font_id = $crayon->setting_val(CrayonSettings::FONT); + if ($font_id != NULL /*&& $font_id != CrayonFonts::DEFAULT_FONT*/) { + echo CrayonResources::fonts()->get_css($font_id); + } + + // Load custom code based on language + $lang = $crayon->setting_val(CrayonSettings::FALLBACK_LANG); + $path = CrayonGlobalSettings::plugin_path() . CRAYON_UTIL_DIR . '/sample/' . $lang . '.txt'; + + if (isset($_POST[self::SAMPLE_CODE])) { + $crayon->code($_POST[self::SAMPLE_CODE]); + } else if ($lang && @file_exists($path)) { + $crayon->url($path); + } else { + $code = " +// A sample class +class Human { + private int age = 0; + public void birthday() { + age++; + print('Happy Birthday!'); + } +} +"; + $crayon->code($code); + } + $crayon->title('Sample Code'); + $crayon->marked('5-7'); + $crayon->output($highlight = true, $nums = true, $print = true); + echo '
'; + crayon_load_plugin_textdomain(); + exit(); + } + + public static function theme($editor = FALSE) { + $db_theme = self::$options[CrayonSettings::THEME]; // Theme name from db + if (!array_key_exists(CrayonSettings::THEME, self::$options)) { + $db_theme = ''; + } + $themes_array = CrayonResources::themes()->get_array(); + // Mark user themes + foreach ($themes_array as $id => $name) { + $mark = CrayonResources::themes()->get($id)->user() ? ' *' : ''; + $themes_array[$id] = array($name, $name . $mark); + } + $missing_theme = !CrayonResources::themes()->is_loaded($db_theme) || !CrayonResources::themes()->exists($db_theme); + self::dropdown(CrayonSettings::THEME, FALSE, FALSE, TRUE, $themes_array, $missing_theme ? CrayonThemes::DEFAULT_THEME : NULL); + if ($editor) { + return; + } + // Theme editor + if (CRAYON_THEME_EDITOR) { + // echo ''. crayon__('Theme Editor') .'
'; + echo '
'; + $buttons = array('edit' => crayon__('Edit'), 'duplicate' => crayon__('Duplicate'), 'submit' => crayon__('Submit'), + 'delete' => crayon__('Delete')); + foreach ($buttons as $k => $v) { + echo '', $v, ''; + } + echo '', self::help_button('http://aramk.com/blog/2012/12/27/crayon-theme-editor/'), '', crayon__("Duplicate a Stock Theme into a User Theme to allow editing."); + echo '
'; + } + // Preview Box + ?> +
+
+
+
+
+
+ ', '', '', ''); ?> +
+
+
+
+ '; + self::checkbox(array(CrayonSettings::ENQUEUE_THEMES, crayon__('Enqueue themes in the header (more efficient).') . self::help_button('http://aramk.com/blog/2012/01/07/enqueuing-themes-and-fonts-in-crayon/'))); + // Check if theme from db is loaded + if ($missing_theme) { + echo '', sprintf(crayon__('The selected theme with id %s could not be loaded'), '' . $db_theme . ''), '. '; + } + } + + public static function font($editor = FALSE) { + $db_font = self::$options[CrayonSettings::FONT]; // Theme name from db + if (!array_key_exists(CrayonSettings::FONT, self::$options)) { + $db_font = ''; + } + $fonts_array = CrayonResources::fonts()->get_array(); + self::dropdown(CrayonSettings::FONT, FALSE, TRUE, TRUE, $fonts_array); + echo ''; + // TODO(aramk) Add this blog article back. + // echo '', crayon__('Add More'), ''; + echo ''; + self::checkbox(array(CrayonSettings::FONT_SIZE_ENABLE, crayon__('Custom Font Size') . ' '), FALSE); + self::input(array('id' => CrayonSettings::FONT_SIZE, 'size' => 2)); + echo '', crayon__('Pixels'), ',  ', crayon__('Line Height'), ' '; + self::input(array('id' => CrayonSettings::LINE_HEIGHT, 'size' => 2)); + echo '', crayon__('Pixels'), '
'; + if ((!CrayonResources::fonts()->is_loaded($db_font) || !CrayonResources::fonts()->exists($db_font))) { + // Default font doesn't actually exist as a file, it means do not override default theme font + echo '', sprintf(crayon__('The selected font with id %s could not be loaded'), '' . $db_font . ''), '.
'; + } + if ($editor) { + return; + } + echo '
'; + self::checkbox(array(CrayonSettings::ENQUEUE_FONTS, crayon__('Enqueue fonts in the header (more efficient).') . self::help_button('http://aramk.com/blog/2012/01/07/enqueuing-themes-and-fonts-in-crayon/'))); + } + + public static function code($editor = FALSE) { + echo '
'; + self::checkbox(array(CrayonSettings::PLAIN, crayon__('Enable plain code view and display') . ' '), FALSE); + self::dropdown(CrayonSettings::SHOW_PLAIN); + echo ''; + self::checkbox(array(CrayonSettings::PLAIN_TOGGLE, crayon__('Enable plain code toggling'))); + self::checkbox(array(CrayonSettings::SHOW_PLAIN_DEFAULT, crayon__('Show the plain code by default'))); + self::checkbox(array(CrayonSettings::COPY, crayon__('Enable code copy/paste'))); + echo ''; + self::checkbox(array(CrayonSettings::POPUP, crayon__('Enable opening code in a window'))); + self::checkbox(array(CrayonSettings::SCROLL, crayon__('Always display scrollbars'))); + self::checkbox(array(CrayonSettings::MINIMIZE, crayon__('Minimize code') . self::help_button('http://aramk.com/blog/2013/01/15/minimizing-code-in-crayon/'))); + self::checkbox(array(CrayonSettings::EXPAND, crayon__('Expand code beyond page borders on mouseover'))); + self::checkbox(array(CrayonSettings::EXPAND_TOGGLE, crayon__('Enable code expanding toggling when possible'))); + echo '
'; + if (!$editor) { + self::checkbox(array(CrayonSettings::DECODE, crayon__('Decode HTML entities in code'))); + } + self::checkbox(array(CrayonSettings::DECODE_ATTRIBUTES, crayon__('Decode HTML entities in attributes'))); + echo '
'; + self::checkbox(array(CrayonSettings::TRIM_WHITESPACE, crayon__('Remove whitespace surrounding the shortcode content'))); + echo '
'; + self::checkbox(array(CrayonSettings::TRIM_CODE_TAG, crayon__('Remove <code> tags surrounding the shortcode content'))); + self::checkbox(array(CrayonSettings::MIXED, crayon__('Allow Mixed Language Highlighting with delimiters and tags.') . self::help_button('http://aramk.com/blog/2011/12/25/mixed-language-highlighting-in-crayon/'))); + echo '
'; + self::checkbox(array(CrayonSettings::SHOW_MIXED, crayon__('Show Mixed Language Icon (+)'))); + echo '
'; + self::checkbox(array(CrayonSettings::TAB_CONVERT, crayon__('Convert tabs to spaces'))); + self::span(crayon__('Tab size in spaces') . ': '); + self::input(array('id' => CrayonSettings::TAB_SIZE, 'size' => 2, 'break' => TRUE)); + self::span(crayon__('Blank lines before code:') . ' '); + self::input(array('id' => CrayonSettings::WHITESPACE_BEFORE, 'size' => 2, 'break' => TRUE)); + self::span(crayon__('Blank lines after code:') . ' '); + self::input(array('id' => CrayonSettings::WHITESPACE_AFTER, 'size' => 2, 'break' => TRUE)); + } + + public static function tags() { + self::checkbox(array(CrayonSettings::INLINE_TAG, crayon__('Capture Inline Tags') . self::help_button('http://aramk.com/blog/2012/03/07/inline-crayons/'))); + self::checkbox(array(CrayonSettings::INLINE_WRAP, crayon__('Wrap Inline Tags') . self::help_button('http://aramk.com/blog/2012/03/07/inline-crayons/'))); + self::checkbox(array(CrayonSettings::CODE_TAG_CAPTURE, crayon__('Capture <code> as')), FALSE); + echo ' '; + self::dropdown(CrayonSettings::CODE_TAG_CAPTURE_TYPE, FALSE); + echo self::help_button('http://aramk.com/blog/2012/03/07/inline-crayons/') . '
'; + self::checkbox(array(CrayonSettings::BACKQUOTE, crayon__('Capture `backquotes` as <code>') . self::help_button('http://aramk.com/blog/2012/03/07/inline-crayons/'))); + self::checkbox(array(CrayonSettings::CAPTURE_PRE, crayon__('Capture <pre> tags as Crayons') . self::help_button('http://aramk.com/blog/2011/12/27/mini-tags-in-crayon/'))); + + echo '
', sprintf(crayon__("Using this markup for Mini Tags and Inline tags is now %sdeprecated%s! Use the %sTag Editor%s instead and convert legacy tags."), '', '', '', ''), '
'; + self::checkbox(array(CrayonSettings::CAPTURE_MINI_TAG, crayon__('Capture Mini Tags like [php][/php] as Crayons.') . self::help_button('http://aramk.com/blog/2011/12/27/mini-tags-in-crayon/'))); + self::checkbox(array(CrayonSettings::INLINE_TAG_CAPTURE, crayon__('Capture Inline Tags like {php}{/php} inside sentences.') . self::help_button('http://aramk.com/blog/2012/03/07/inline-crayons/'))); + self::checkbox(array(CrayonSettings::PLAIN_TAG, crayon__('Enable [plain][/plain] tag.') . self::help_button('http://aramk.com/blog/2011/12/27/mini-tags-in-crayon/'))); + } + + public static function files() { + echo ''; + echo crayon__('When loading local files and a relative path is given for the URL, use the absolute path'), ': ', + '
', home_url(), '/'; + self::input(array('id' => CrayonSettings::LOCAL_PATH)); + echo '
', crayon__('Followed by your relative URL.'); + } + + public static function tag_editor() { + $can_convert = self::load_legacy_posts(); + if ($can_convert) { + $disabled = ''; + $convert_text = crayon__('Convert Legacy Tags'); + } else { + $disabled = 'disabled="disabled"'; + $convert_text = crayon__('No Legacy Tags Found'); + } + + echo '  '; + self::checkbox(array('convert_encode', crayon__("Encode")), FALSE); + echo self::help_button('http://aramk.com/blog/2012/09/26/converting-legacy-tags-to-pre/'), CRAYON_BR, CRAYON_BR; + $sep = sprintf(crayon__('Use %s to separate setting names from values in the <pre> class attribute'), + self::dropdown(CrayonSettings::ATTR_SEP, FALSE, FALSE, FALSE)); + echo '', $sep, self::help_button('http://aramk.com/blog/2012/03/25/crayon-tag-editor/'), '
'; + self::checkbox(array(CrayonSettings::TAG_EDITOR_FRONT, crayon__("Display the Tag Editor in any TinyMCE instances on the frontend (e.g. bbPress)") . self::help_button('http://aramk.com/blog/2012/09/08/crayon-with-bbpress/'))); + self::checkbox(array(CrayonSettings::TAG_EDITOR_SETTINGS, crayon__("Display Tag Editor settings on the frontend"))); + self::span(crayon__('Add Code button text') . ' '); + self::input(array('id' => CrayonSettings::TAG_EDITOR_ADD_BUTTON_TEXT, 'break' => TRUE)); + self::span(crayon__('Edit Code button text') . ' '); + self::input(array('id' => CrayonSettings::TAG_EDITOR_EDIT_BUTTON_TEXT, 'break' => TRUE)); + self::span(crayon__('Quicktag button text') . ' '); + self::input(array('id' => CrayonSettings::TAG_EDITOR_QUICKTAG_BUTTON_TEXT, 'break' => TRUE)); + } + + public static function misc() { + echo crayon__('Clear the cache used to store remote code requests'), ': '; + self::dropdown(CrayonSettings::CACHE, false); + echo '
'; + self::checkbox(array(CrayonSettings::EFFICIENT_ENQUEUE, crayon__('Attempt to load Crayon\'s CSS and JavaScript only when needed') . self::help_button('http://aramk.com/blog/2012/01/23/failing-to-load-crayons-on-pages/'))); + self::checkbox(array(CrayonSettings::SAFE_ENQUEUE, crayon__('Disable enqueuing for page templates that may contain The Loop.') . self::help_button('http://aramk.com/blog/2012/01/23/failing-to-load-crayons-on-pages/'))); + self::checkbox(array(CrayonSettings::COMMENTS, crayon__('Allow Crayons inside comments'))); + self::checkbox(array(CrayonSettings::EXCERPT_STRIP, crayon__('Remove Crayons from excerpts'))); + self::checkbox(array(CrayonSettings::MAIN_QUERY, crayon__('Load Crayons only from the main Wordpress query'))); + self::checkbox(array(CrayonSettings::TOUCHSCREEN, crayon__('Disable mouse gestures for touchscreen devices (eg. MouseOver)'))); + self::checkbox(array(CrayonSettings::DISABLE_ANIM, crayon__('Disable animations'))); + self::checkbox(array(CrayonSettings::DISABLE_RUNTIME, crayon__('Disable runtime stats'))); + echo '' . crayon__('Disable for posts before') . ': '; + self::input(array('id' => CrayonSettings::DISABLE_DATE, 'type' => 'date', 'size' => 8, 'break' => FALSE)); + echo '
'; + self::checkbox(array(CrayonSettings::DELAY_LOAD_JS, crayon__('Load scripts in the page footer using wp_footer() to improve loading performance.'))); + } + + // Debug Fields =========================================================== + + public static function errors() { + self::checkbox(array(CrayonSettings::ERROR_LOG, crayon__('Log errors for individual Crayons'))); + self::checkbox(array(CrayonSettings::ERROR_LOG_SYS, crayon__('Log system-wide errors'))); + self::checkbox(array(CrayonSettings::ERROR_MSG_SHOW, crayon__('Display custom message for errors'))); + self::input(array('id' => CrayonSettings::ERROR_MSG, 'size' => 60, 'margin' => TRUE)); + } + + public static function log() { + $log = CrayonLog::log(); + touch(CRAYON_LOG_FILE); + $exists = file_exists(CRAYON_LOG_FILE); + $writable = is_writable(CRAYON_LOG_FILE); + if (!empty($log)) { + echo '
', '
', $log, + '
', '
', + ' ', + ' ', ' ', + ' ', '
', '
'; + } + echo '', (empty($log)) ? crayon__('The log is currently empty.') . ' ' : ''; + if ($exists) { + $writable ? crayon_e('The log file exists and is writable.') : crayon_e('The log file exists and is not writable.'); + } else { + crayon_e('The log file does not exist and is not writable.'); + } + echo ''; + } + + // About Fields =========================================================== + + public static function info() { + global $CRAYON_VERSION, $CRAYON_DATE, $CRAYON_AUTHOR, $CRAYON_WEBSITE, $CRAYON_TWITTER, $CRAYON_GIT, $CRAYON_PLUGIN_WP, $CRAYON_AUTHOR_SITE, $CRAYON_EMAIL, $CRAYON_DONATE; + echo ''; + $version = '' . crayon__('Version') . ': ' . $CRAYON_VERSION; + $date = $CRAYON_DATE; + $developer = '' . crayon__('Developer') . ': ' . '' . $CRAYON_AUTHOR . ''; + $translators = '' . crayon__('Translators') . ': ' . + ' + Arabic (Djennad Hamza), + Chinese Simplified (Dezhi Liu, Jash Yin), + Chinese Traditional (Arefly), + Dutch (Robin Roelofsen, Chilion Snoek), + French (Victor Felder), + Finnish (vahalan), + German (Stephan Knauß), + Italian (Federico Bellucci), + Japanese (@west_323), + Korean (dokenzy), + Lithuanian (Vincent G), + Norwegian (Jackalworks), + Persian (MahdiY), + Polish (Bartosz Romanowski, Robert Korulczyk), + Portuguese (Adonai S. Canez), + Russian (Minimus, Di_Skyer), + Slovak (webhostgeeks), + Slovenian (Jan Sušnik), + Spanish (Hermann Bravo), + Tamil (KKS21199), + Turkish (Hakan), + Ukrainian (Michael Yunat)'; + + $links = ' + + + + + +
+ +
'; + + echo ' + + + + + + + + + + + + + +
' . $version . ' - ' . $date . '
' . $developer . '
' . $translators . '
' . $links . '
'; + + } + + public static function help_button($link) { + return ' ' . crayon__('?') . ''; + } + + public static function plugin_row_meta($meta, $file) { + global $CRAYON_DONATE; + if ($file == CrayonWP::basename()) { + $meta[] = '' . crayon__('Settings') . ''; + $meta[] = '' . crayon__('Theme Editor') . ''; + $meta[] = '' . crayon__('Donate') . ''; + } + return $meta; + } +} + +// Add the settings menus + +if (defined('ABSPATH') && is_admin()) { + // For the admin section + add_action('admin_menu', 'CrayonSettingsWP::admin_load'); + add_filter('plugin_row_meta', 'CrayonSettingsWP::plugin_row_meta', 10, 2); +} + +?> diff --git a/crayon_themes.class.php b/crayon_themes.class.php new file mode 100644 index 0000000..a452018 --- /dev/null +++ b/crayon_themes.class.php @@ -0,0 +1,45 @@ +set_default(self::DEFAULT_THEME, self::DEFAULT_THEME_NAME); + $this->directory(CRAYON_THEME_PATH); + $this->relative_directory(CRAYON_THEME_DIR); + $this->extension('css'); + + CrayonLog::debug("Setting theme directories"); + $upload = CrayonGlobalSettings::upload_path(); + if ($upload) { + $this->user_directory($upload . CRAYON_THEME_DIR); + if (!is_dir($this->user_directory())) { + CrayonGlobalSettings::mkdir($this->user_directory()); + CrayonLog::debug($this->user_directory(), "THEME USER DIR"); + } + } else { + CrayonLog::syslog("Upload directory is empty: " . $upload . " cannot load themes."); + } + CrayonLog::debug($this->directory()); + CrayonLog::debug($this->user_directory()); + } + + // XXX Override + public function filename($id, $user = NULL) { + return CrayonUtil::path_slash($id) . parent::filename($id, $user); + } + +} + +?> \ No newline at end of file diff --git a/crayon_wp.class.php b/crayon_wp.class.php new file mode 100644 index 0000000..ca0d418 --- /dev/null +++ b/crayon_wp.class.php @@ -0,0 +1,1340 @@ + '_2.7.2_beta', + 'Date' => '25th April, 2015', + 'AuthorName' => 'Aram Kocharyan', + 'PluginURI' => 'https://github.com/aramk/crayon-syntax-highlighter', +)); + +/* The plugin class that manages all other classes and integrates Crayon with WP */ + +class CrayonWP { + // Properties and Constants =============================================== + + // Associative array, keys are post IDs as strings and values are number of crayons parsed as ints + private static $post_queue = array(); + // Ditto for comments + private static $comment_queue = array(); + private static $post_captures = array(); + private static $comment_captures = array(); + // Whether we are displaying an excerpt + private static $is_excerpt = FALSE; + // Whether we have added styles and scripts + private static $enqueued = FALSE; + // Whether we have already printed the wp head + private static $wp_head = FALSE; + // Used to keep Crayon IDs + private static $next_id = 0; + // String to store the regex for capturing tags + private static $alias_regex = ''; + private static $tags_regex = ''; + private static $tags_regex_legacy = ''; + private static $tag_regexes = array(); + // Defined constants used in bitwise flags + private static $tag_types = array( + CrayonSettings::CAPTURE_MINI_TAG, + CrayonSettings::CAPTURE_PRE, + CrayonSettings::INLINE_TAG, + CrayonSettings::PLAIN_TAG, + CrayonSettings::BACKQUOTE); + private static $tag_bits = array(); + // Used to find legacy tags + private static $legacy_flags = NULL; + + // Used to detect the shortcode + private static $allowed_atts = array('url' => NULL, 'lang' => NULL, 'title' => NULL, 'mark' => NULL, 'range' => NULL, 'inline' => NULL); + const REGEX_CLOSED = '(?:\[\s*crayon(?:-(\w+))?\b([^\]]*)/\s*\])'; // [crayon atts="" /] + const REGEX_TAG = '(?:\[\s*crayon(?:-(\w+))?\b([^\]]*)\](.*?)\[\s*/\s*crayon\s*\])'; // [crayon atts=""] ... [/crayon] + const REGEX_INLINE_CLASS = '\bcrayon-inline\b'; + + const REGEX_CLOSED_NO_CAPTURE = '(?:\[\s*crayon\b[^\]]*/\])'; + const REGEX_TAG_NO_CAPTURE = '(?:\[\s*crayon\b[^\]]*\].*?\[/crayon\])'; + + const REGEX_QUICK_CAPTURE = '(?:\[\s*crayon[^\]]*\].*?\[\s*/\s*crayon\s*\])|(?:\[\s*crayon[^\]]*/\s*\])'; + + const REGEX_BETWEEN_PARAGRAPH = '(?:[^<]*<(?!/?p(\s+[^>]*)?>)[^>]+(\s+[^>]*)?>)*[^<]*((?:\[\s*crayon[^\]]*\].*?\[\s*/\s*crayon\s*\])|(?:\[\s*crayon[^\]]*/\s*\]))(?:[^<]*<(?!/?p(\s+[^>]*)?>)[^>]+(\s+[^>]*)?>)*[^<]*'; + const REGEX_BETWEEN_PARAGRAPH_SIMPLE = '(]*)?>)(.*?)(]*)?>)'; + + // For [crayon-id/] + const REGEX_BR_BEFORE = '#<\s*br\s*/?\s*>\s*(\[\s*crayon-\w+\])#msi'; + const REGEX_BR_AFTER = '#(\[\s*crayon-\w+\])\s*<\s*br\s*/?\s*>#msi'; + + const REGEX_ID = '#(?url($url); + $crayon->code($content); + // Set attributes, should be set after URL to allow language auto detection + $crayon->language($lang); + $crayon->title($title); + $crayon->marked($mark); + $crayon->range($range); + + $crayon->is_inline($inline); + + // Determine if we should highlight + $highlight = array_key_exists('highlight', $atts) ? CrayonUtil::str_to_bool($atts['highlight'], FALSE) : TRUE; + $crayon->is_highlighted($highlight); + return $crayon; + } + + /* Returns Crayon instance */ + public static function instance($extra_attr = array(), $id = NULL) { + CrayonLog::debug('instance'); + + // Create Crayon + $crayon = new CrayonHighlighter(); + + /* Load settings and merge shortcode attributes which will override any existing. + * Stores the other shortcode attributes as settings in the crayon. */ + if (!empty($extra_attr)) { + $crayon->settings($extra_attr); + } + if (!empty($id)) { + $crayon->id($id); + } + + return $crayon; + } + + /* For manually highlighting code, useful for other PHP contexts */ + public static function highlight($code, $add_tags = FALSE, $output_text = FALSE) { + $captures = CrayonWP::capture_crayons(0, $code); + $the_captures = $captures['capture']; + if (count($the_captures) == 0 && $add_tags) { + // Nothing captured, so wrap in a pre and try again + $code = '
' . $code . '
'; + $captures = CrayonWP::capture_crayons(0, $code); + $the_captures = $captures['capture']; + } + $the_content = $captures['content']; + $the_content = CrayonUtil::strip_tags_blacklist($the_content, array('script')); + $the_content = CrayonUtil::strip_event_attributes($the_content); + foreach ($the_captures as $id => $capture) { + $atts = $capture['atts']; + $no_enqueue = array( + CrayonSettings::ENQUEUE_THEMES => FALSE, + CrayonSettings::ENQUEUE_FONTS => FALSE); + $atts = array_merge($atts, $no_enqueue); + $code = $capture['code']; + $crayon = CrayonWP::shortcode($atts, $code, $id); + $crayon_formatted = $crayon->output(TRUE, FALSE); + $the_content = CrayonUtil::preg_replace_escape_back(self::regex_with_id($id), $crayon_formatted, $the_content, 1, $count); + } + + if ($output_text) { + header('Content-Type: text/plain'); + } else { + header('Content-Type: text/html'); + } + return $the_content; + } + + public static function ajax_highlight() { + $code = isset($_POST['code']) ? $_POST['code'] : null; + if (!$code) { + $code = isset($_GET['code']) ? $_GET['code'] : null; + } + if ($code) { + echo self::highlight($code, FALSE, TRUE); + } else { + echo "No code specified."; + } + exit(); + } + + /* Uses the main query */ + public static function wp() { + CrayonLog::debug('wp (global)'); + global $wp_the_query; + if (isset($wp_the_query->posts)) { + $posts = $wp_the_query->posts; + self::the_posts($posts); + } + } + + // TODO put args into an array + public static function capture_crayons($wp_id, $wp_content, $extra_settings = array(), $args = array()) { + extract($args); + CrayonUtil::set_var($callback, NULL); + CrayonUtil::set_var($callback_extra_args, NULL); + CrayonUtil::set_var($ignore, TRUE); + CrayonUtil::set_var($preserve_atts, FALSE); + CrayonUtil::set_var($flags, NULL); + CrayonUtil::set_var($skip_setting_check, FALSE); + CrayonUtil::set_var($just_check, FALSE); + + // Will contain captured crayons and altered $wp_content + $capture = array('capture' => array(), 'content' => $wp_content, 'has_captured' => FALSE); + + // Do not apply Crayon for posts older than a certain date. + $disable_date = trim(CrayonGlobalSettings::val(CrayonSettings::DISABLE_DATE)); + if ($disable_date && get_post_time('U', true, $wp_id) <= strtotime($disable_date)) { + return $capture; + } + + // Flags for which Crayons to convert + $in_flag = self::in_flag($flags); + + CrayonLog::debug('capture for id ' . $wp_id . ' len ' . strlen($wp_content)); + + // Convert
 tags to crayon tags, if needed
+        if ((CrayonGlobalSettings::val(CrayonSettings::CAPTURE_PRE) || $skip_setting_check) && $in_flag[CrayonSettings::CAPTURE_PRE]) {
+            // XXX This will fail if 
 is used inside another 

+            $wp_content = preg_replace_callback('#(?]*)\bclass\s*=\s*(["\'])(.*?)\2([^>]*))?)([^>]*)>(.*?)<\s*/\s*pre\s*>#msi', 'CrayonWP::pre_tag', $wp_content);
+        }
+
+        // Convert mini [php][/php] tags to crayon tags, if needed
+        if ((CrayonGlobalSettings::val(CrayonSettings::CAPTURE_MINI_TAG) || $skip_setting_check) && $in_flag[CrayonSettings::CAPTURE_MINI_TAG]) {
+            $wp_content = preg_replace('#(? to inline tags
+        if (CrayonGlobalSettings::val(CrayonSettings::CODE_TAG_CAPTURE)) {
+            $inline = CrayonGlobalSettings::val(CrayonSettings::CODE_TAG_CAPTURE_TYPE) === 0;
+            $inline_setting = $inline ? 'inline="true"' : '';
+            $wp_content = preg_replace('#<(\s*code\b)([^>]*)>(.*?)]*>#msi', '[crayon ' . $inline_setting . ' \2]\3[/crayon]', $wp_content);
+        }
+
+        if ((CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG) || $skip_setting_check) && $in_flag[CrayonSettings::INLINE_TAG]) {
+            if (CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG_CAPTURE)) {
+                // Convert inline {php}{/php} tags to crayon tags, if needed
+                $wp_content = preg_replace('#(? tags to inline crayon tags
+            $wp_content = preg_replace_callback('#(?]*)\bclass\s*=\s*(["\'])(.*?)\2([^>]*)>(.*?)<\s*/\s*span\s*>#msi', 'CrayonWP::span_tag', $wp_content);
+        }
+
+        // Convert [plain] tags into 
, if needed + if ((CrayonGlobalSettings::val(CrayonSettings::PLAIN_TAG) || $skip_setting_check) && $in_flag[CrayonSettings::PLAIN_TAG]) { + $wp_content = preg_replace_callback('#(?get($theme_id); + // If theme not found, use fallbacks + if (!$theme) { + // Given theme is invalid, try global setting + $theme_id = CrayonGlobalSettings::val(CrayonSettings::THEME); + $theme = CrayonResources::themes()->get($theme_id); + if (!$theme) { + // Global setting is invalid, fall back to default + $theme = CrayonResources::themes()->get_default(); + $theme_id = CrayonThemes::DEFAULT_THEME; + } + } + // If theme is now valid, change the array + if ($theme) { + if (!$preserve_atts || isset($atts_array[CrayonSettings::THEME])) { + $atts_array[CrayonSettings::THEME] = $theme_id; + } + $theme->used(TRUE); + } + + // Capture font + $font_id = array_key_exists(CrayonSettings::FONT, $atts_array) ? $atts_array[CrayonSettings::FONT] : ''; + $font = CrayonResources::fonts()->get($font_id); + // If font not found, use fallbacks + if (!$font) { + // Given font is invalid, try global setting + $font_id = CrayonGlobalSettings::val(CrayonSettings::FONT); + $font = CrayonResources::fonts()->get($font_id); + if (!$font) { + // Global setting is invalid, fall back to default + $font = CrayonResources::fonts()->get_default(); + $font_id = CrayonFonts::DEFAULT_FONT; + } + } + + // If font is now valid, change the array + if ($font /* != NULL && $font_id != CrayonFonts::DEFAULT_FONT*/) { + if (!$preserve_atts || isset($atts_array[CrayonSettings::FONT])) { + $atts_array[CrayonSettings::FONT] = $font_id; + } + $font->used(TRUE); + } + + // Add array of atts and content to post queue with key as post ID + // XXX If at this point no ID is added we have failed! + $id = !empty($open_ids[$i]) ? $open_ids[$i] : $closed_ids[$i]; + //if ($ignore) { + $code = self::crayon_remove_ignore($contents[$i]); + //} + $c = array('post_id' => $wp_id, 'atts' => $atts_array, 'code' => $code); + $capture['capture'][$id] = $c; + CrayonLog::debug('capture finished for post id ' . $wp_id . ' crayon-id ' . $id . ' atts: ' . count($atts_array) . ' code: ' . strlen($code)); + $is_inline = isset($atts_array['inline']) && CrayonUtil::str_to_bool($atts_array['inline'], FALSE) ? '-i' : ''; + if ($callback === NULL) { + $wp_content = str_replace($full_matches[$i], '[crayon-' . $id . $is_inline . '/]', $wp_content); + } else { + $wp_content = call_user_func($callback, $c, $full_matches[$i], $id, $is_inline, $wp_content, $callback_extra_args); + } + } + + } + + if ($ignore) { + // We need to escape ignored Crayons, since they won't be captured + // XXX Do this after replacing the Crayon with the shorter ID tag, otherwise $full_matches will be different from $wp_content + $wp_content = self::crayon_remove_ignore($wp_content); + } + + $result = self::replace_backquotes($wp_content); + $wp_content = $result['content']; + + $capture['content'] = $wp_content; + return $capture; + } + + public static function replace_backquotes($wp_content) { + // Convert `` backquote tags into , if needed + // XXX Some code may contain `` so must do it after all Crayons are captured + $result = array(); + $prev_count = strlen($wp_content); + if (CrayonGlobalSettings::val(CrayonSettings::BACKQUOTE)) { + $wp_content = preg_replace('#(?$1', $wp_content); + } + $result['changed'] = $prev_count !== strlen($wp_content); + $result['content'] = $wp_content; + return $result; + } + + /* Search for Crayons in posts and queue them for creation */ + public static function the_posts($posts) { + CrayonLog::debug('the_posts'); + + // Whether to enqueue syles/scripts + CrayonSettingsWP::load_settings(TRUE); // We will eventually need more than the settings + + self::init_tags_regex(); + $crayon_posts = CrayonSettingsWP::load_posts(); // Loads posts containing crayons + + // Search for shortcode in posts + foreach ($posts as $post) { + $wp_id = $post->ID; + $is_page = $post->post_type == 'page'; + if (!in_array($wp_id, $crayon_posts)) { + // If we get query for a page, then that page might have a template and load more posts containing Crayons + // By this state, we would be unable to enqueue anything (header already written). + if (CrayonGlobalSettings::val(CrayonSettings::SAFE_ENQUEUE) && $is_page) { + CrayonGlobalSettings::set(CrayonSettings::ENQUEUE_THEMES, false); + CrayonGlobalSettings::set(CrayonSettings::ENQUEUE_FONTS, false); + } + // Only include crayon posts + continue; + } + + $id_str = strval($wp_id); + + if (wp_is_post_revision($wp_id)) { + // Ignore post revisions, use the parent, which has the updated post content + continue; + } + + if (isset(self::$post_captures[$id_str])) { + // Don't capture twice + // XXX post->post_content is reset each loop, replace content + // Doing this might cause content changed by other plugins between the last loop + // to fail, so be cautious + $post->post_content = self::$post_captures[$id_str]; + continue; + } + // Capture post Crayons + $captures = self::capture_crayons(intval($post->ID), $post->post_content); + + // XXX Careful not to undo changes by other plugins + // XXX Must replace to remove $ for ignored Crayons + $post->post_content = $captures['content']; + self::$post_captures[$id_str] = $captures['content']; + if ($captures['has_captured'] === TRUE) { + self::$post_queue[$id_str] = array(); + foreach ($captures['capture'] as $capture_id => $capture_content) { + self::$post_queue[$id_str][$capture_id] = $capture_content; + } + } + + // Search for shortcode in comments + if (CrayonGlobalSettings::val(CrayonSettings::COMMENTS)) { + $comments = get_comments(array('post_id' => $post->ID)); + foreach ($comments as $comment) { + $id_str = strval($comment->comment_ID); + if (isset(self::$comment_queue[$id_str])) { + // Don't capture twice + continue; + } + // Capture comment Crayons, decode their contents if decode not specified + $content = apply_filters('get_comment_text', $comment->comment_content, $comment); + $captures = self::capture_crayons($comment->comment_ID, $content, array(CrayonSettings::DECODE => TRUE)); + self::$comment_captures[$id_str] = $captures['content']; + if ($captures['has_captured'] === TRUE) { + self::$comment_queue[$id_str] = array(); + foreach ($captures['capture'] as $capture_id => $capture_content) { + self::$comment_queue[$id_str][$capture_id] = $capture_content; + } + } + } + } + } + + return $posts; + } + + private static function add_crayon_id($content) { + $uid = $content[0] . '-' . str_replace('.', '', uniqid('', true)); + CrayonLog::debug('add_crayon_id ' . $uid); + return $uid; + } + + private static function get_crayon_id() { + return self::$next_id++; + } + + public static function enqueue_resources() { + if (!self::$enqueued) { + + CrayonLog::debug('enqueue'); + global $CRAYON_VERSION; + CrayonSettingsWP::load_settings(TRUE); + if (CRAYON_MINIFY) { + wp_enqueue_style('crayon', plugins_url(CRAYON_STYLE_MIN, __FILE__), array(), $CRAYON_VERSION); + wp_enqueue_script('crayon_js', plugins_url(CRAYON_JS_MIN, __FILE__), array('jquery'), $CRAYON_VERSION, CrayonGlobalSettings::val(CrayonSettings::DELAY_LOAD_JS)); + } else { + wp_enqueue_style('crayon_style', plugins_url(CRAYON_STYLE, __FILE__), array(), $CRAYON_VERSION); + wp_enqueue_style('crayon_global_style', plugins_url(CRAYON_STYLE_GLOBAL, __FILE__), array(), $CRAYON_VERSION); + wp_enqueue_script('crayon_util_js', plugins_url(CRAYON_JS_UTIL, __FILE__), array('jquery'), $CRAYON_VERSION); + CrayonSettingsWP::other_scripts(); + } + CrayonSettingsWP::init_js_settings(); + self::$enqueued = TRUE; + } + } + + private static function init_tags_regex($force = FALSE, $flags = NULL, &$tags_regex = NULL) { + CrayonSettingsWP::load_settings(); + self::init_tag_bits(); + + // Default output + if ($tags_regex === NULL) { + $tags_regex = & self::$tags_regex; + } + + if ($force || $tags_regex === "") { + // Check which tags are in $flags. If it's NULL, then all flags are true. + $in_flag = self::in_flag($flags); + + if (($in_flag[CrayonSettings::CAPTURE_MINI_TAG] && (CrayonGlobalSettings::val(CrayonSettings::CAPTURE_MINI_TAG)) || $force) || + ($in_flag[CrayonSettings::INLINE_TAG] && (CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG) && CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG_CAPTURE)) || $force) + ) { + $aliases = CrayonResources::langs()->ids_and_aliases(); + self::$alias_regex = ''; + for ($i = 0; $i < count($aliases); $i++) { + $alias = $aliases[$i]; + $alias_regex = CrayonUtil::esc_hash(CrayonUtil::esc_regex($alias)); + if ($i != count($aliases) - 1) { + $alias_regex .= '|'; + } + self::$alias_regex .= $alias_regex; + } + } + + // Add other tags + $tags_regex = '#(? '(\[\s*(' . self::$alias_regex . ')\b)', + CrayonSettings::CAPTURE_PRE => '(<\s*pre\b)', + CrayonSettings::INLINE_TAG => '(' . self::REGEX_INLINE_CLASS . ')' . '|(\{\s*(' . self::$alias_regex . ')\b([^\}]*)\})', + CrayonSettings::PLAIN_TAG => '(\s*\[\s*plain\b)', + CrayonSettings::BACKQUOTE => '(`[^`]*`)' + ); + + foreach ($tag_regexes as $tag => $regex) { + if ($in_flag[$tag] && (CrayonGlobalSettings::val($tag) || $force)) { + $tags_regex .= '|' . $regex; + } + } + $tags_regex .= ')#msi'; + } + + } + + private static function init_tag_bits() { + if (count(self::$tag_bits) == 0) { + $values = array(); + for ($i = 0; $i < count(self::$tag_types); $i++) { + $j = pow(2, $i); + self::$tag_bits[self::$tag_types[$i]] = $j; + } + } + } + + public static function tag_bit($tag) { + self::init_tag_bits(); + if (isset(self::$tag_bits[$tag])) { + return self::$tag_bits[$tag]; + } else { + return null; + } + } + + public static function in_flag($flags) { + $in_flag = array(); + foreach (self::$tag_types as $tag) { + $in_flag[$tag] = $flags === NULL || ($flags & self::tag_bit($tag)) > 0; + } + return $in_flag; + } + + private static function init_legacy_tag_bits() { + if (self::$legacy_flags === NULL) { + self::$legacy_flags = self::tag_bit(CrayonSettings::CAPTURE_MINI_TAG) | + self::tag_bit(CrayonSettings::INLINE_TAG) | + self::tag_bit(CrayonSettings::PLAIN_TAG); + } + if (self::$tags_regex_legacy === "") { + self::init_tags_regex(TRUE, self::$legacy_flags, self::$tags_regex_legacy); + } + } + + // Add Crayon into the_content + public static function the_content($the_content) { + CrayonLog::debug('the_content'); + + // Some themes make redundant queries and don't need extra work... + if (strlen($the_content) == 0) { + CrayonLog::debug('the_content blank'); + return $the_content; + } + + global $post; + + // Go through queued posts and find crayons + $post_id = strval($post->ID); + + if (self::$is_excerpt) { + CrayonLog::debug('excerpt'); + if (CrayonGlobalSettings::val(CrayonSettings::EXCERPT_STRIP)) { + CrayonLog::debug('excerpt strip'); + // Remove Crayon from content if we are displaying an excerpt + $the_content = preg_replace(self::REGEX_WITH_ID, '', $the_content); + } + // Otherwise Crayon remains with ID and replaced later + return $the_content; + } + + // Find if this post has Crayons + if (array_key_exists($post_id, self::$post_queue)) { + self::enqueue_resources(); + + // XXX We want the plain post content, no formatting + $the_content_original = $the_content; + + // Replacing may cause

tags to become disjoint with a

inside them, close and reopen them if needed + $the_content = preg_replace_callback('#' . self::REGEX_BETWEEN_PARAGRAPH_SIMPLE . '#msi', 'CrayonWP::add_paragraphs', $the_content); + // Loop through Crayons + $post_in_queue = self::$post_queue[$post_id]; + + foreach ($post_in_queue as $id => $v) { + $atts = $v['atts']; + $content = $v['code']; // The code we replace post content with + $crayon = self::shortcode($atts, $content, $id); + if (is_feed()) { + // Convert the plain code to entities and put in a
 tag
+                    $crayon_formatted = CrayonFormatter::plain_code($crayon->code(), $crayon->setting_val(CrayonSettings::DECODE));
+                } else {
+                    // Apply shortcode to the content
+                    $crayon_formatted = $crayon->output(TRUE, FALSE);
+                }
+                // Replace the code with the Crayon
+                CrayonLog::debug('the_content: id ' . $post_id . ' has UID ' . $id . ' : ' . intval(stripos($the_content, $id) !== FALSE));
+                $the_content = CrayonUtil::preg_replace_escape_back(self::regex_with_id($id), $crayon_formatted, $the_content, 1, $count);
+                CrayonLog::debug('the_content: REPLACED for id ' . $post_id . ' from len ' . strlen($the_content_original) . ' to ' . strlen($the_content));
+            }
+        }
+
+        return $the_content;
+    }
+
+    public static function pre_comment_text($text) {
+        global $comment;
+        $comment_id = strval($comment->comment_ID);
+        if (array_key_exists($comment_id, self::$comment_captures)) {
+            // Replace with IDs now that we need to
+            $text = self::$comment_captures[$comment_id];
+        }
+        return $text;
+    }
+
+    public static function comment_text($text) {
+        global $comment;
+        $comment_id = strval($comment->comment_ID);
+        // Find if this post has Crayons
+        if (array_key_exists($comment_id, self::$comment_queue)) {
+            // XXX We want the plain post content, no formatting
+            $the_content_original = $text;
+            // Loop through Crayons
+            $post_in_queue = self::$comment_queue[$comment_id];
+
+            foreach ($post_in_queue as $id => $v) {
+                $atts = $v['atts'];
+                $content = $v['code']; // The code we replace post content with
+                $crayon = self::shortcode($atts, $content, $id);
+                $crayon_formatted = $crayon->output(TRUE, FALSE);
+                // Replacing may cause 

tags to become disjoint with a

inside them, close and reopen them if needed + if (!$crayon->is_inline()) { + $text = preg_replace_callback('#' . self::REGEX_BETWEEN_PARAGRAPH_SIMPLE . '#msi', 'CrayonWP::add_paragraphs', $text); + } + // Replace the code with the Crayon + $text = CrayonUtil::preg_replace_escape_back(self::regex_with_id($id), $crayon_formatted, $text, 1, $text); + } + } + return $text; + } + + public static function add_paragraphs($capture) { + if (count($capture) != 4) { + CrayonLog::debug('add_paragraphs: 0'); + return $capture[0]; + } + $capture[2] = preg_replace('#(?:<\s*br\s*/\s*>\s*)?(\[\s*crayon-\w+/\])(?:<\s*br\s*/\s*>\s*)?#msi', '

$1

', $capture[2]); + // If [crayon appears right after

then we will generate

, remove all these + $paras = $capture[1] . $capture[2] . $capture[3]; + return $paras; + } + + // Remove Crayons from the_excerpt + public static function the_excerpt($the_excerpt) { + CrayonLog::debug('excerpt'); + global $post; + if (!empty($post->post_excerpt)) { + // Use custom excerpt if defined + $the_excerpt = wpautop($post->post_excerpt); + } else { + // Pass wp_trim_excerpt('') to gen from content (and remove [crayons]) + $the_excerpt = wpautop(wp_trim_excerpt('')); + } + // XXX Returning "" may cause it to default to full contents... + return $the_excerpt . ' '; + } + + // Used to capture pre and span tags which have settings in class attribute + public static function class_tag($matches) { + // If class exists, atts is not captured + $pre_class = $matches[1]; + $quotes = $matches[2]; + $class = $matches[3]; + $post_class = $matches[4]; + $atts = $matches[5]; + $content = $matches[6]; + + // If we find a crayon=false in the attributes, or a crayon[:_]false in the class, then we should not capture + $ignore_regex_atts = '#crayon\s*=\s*(["\'])\s*(false|no|0)\s*\1#msi'; + $ignore_regex_class = '#crayon\s*[:_]\s*(false|no|0)#msi'; + if (preg_match($ignore_regex_atts, $atts) !== 0 || + preg_match($ignore_regex_class, $class) !== 0 + ) { + return $matches[0]; + } + + if (!empty($class)) { + if (preg_match('#\bignore\s*:\s*true#', $class)) { + // Prevent any changes if ignoring the tag. + return $matches[0]; + } + // crayon-inline is turned into inline="1" + $class = preg_replace('#' . self::REGEX_INLINE_CLASS . '#mi', 'inline="1"', $class); + // "setting[:_]value" style settings in the class attribute + $class = preg_replace('#\b([A-Za-z-]+)[_:](\S+)#msi', '$1=' . $quotes . '$2' . $quotes, $class); + } + + // data-url is turned into url="" + if (!empty($post_class)) { + $post_class = preg_replace('#\bdata-url\s*=#mi', 'url=', $post_class); + } + if (!empty($pre_class)) { + $pre_class = preg_replace('#\bdata-url\s*=#mi', 'url=', $pre_class); + } + + if (!empty($class)) { + return "[crayon $pre_class $class $post_class]{$content}[/crayon]"; + } else { + return "[crayon $atts]{$content}[/crayon]"; + } + } + + // Capture span tag and extract settings from the class attribute, if present. + public static function span_tag($matches) { + // Only use tags with crayon-inline class + if (preg_match('#' . self::REGEX_INLINE_CLASS . '#mi', $matches[3])) { + // no $atts + $matches[6] = $matches[5]; + $matches[5] = ''; + return self::class_tag($matches); + } else { + // Don't turn regular s into Crayons + return $matches[0]; + } + } + + // Capture pre tag and extract settings from the class attribute, if present. + public static function pre_tag($matches) { + return self::class_tag($matches); + } + + /** + * Check if the $ notation has been used to ignore [crayon] tags within posts and remove all matches + * Can also remove if used without $ as a regular crayon + * + * @deprecated + */ + public static function crayon_remove_ignore($the_content, $ignore_flag = '$') { + if ($ignore_flag == FALSE) { + $ignore_flag = ''; + } + $ignore_flag_regex = preg_quote($ignore_flag); + + $the_content = preg_replace('#' . $ignore_flag_regex . '(\s*\[\s*crayon)#msi', '$1', $the_content); + $the_content = preg_replace('#(crayon\s*\])\s*\$#msi', '$1', $the_content); + + if (CrayonGlobalSettings::val(CrayonSettings::CAPTURE_PRE)) { + $the_content = str_ireplace(array($ignore_flag . '' . $ignore_flag), array(''), $the_content); + // Remove any tags wrapping around the whole code, since we won't needed them + // XXX This causes tags to be stripped in the post content! Disabled now. + // $the_content = preg_replace('#(^\s*<\s*code[^>]*>)|(<\s*/\s*code[^>]*>\s*$)#msi', '', $the_content); + } + if (CrayonGlobalSettings::val(CrayonSettings::PLAIN_TAG)) { + $the_content = str_ireplace(array($ignore_flag . '[plain', 'plain]' . $ignore_flag), array('[plain', 'plain]'), $the_content); + } + if (CrayonGlobalSettings::val(CrayonSettings::CAPTURE_MINI_TAG) || + (CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG && CrayonGlobalSettings::val(CrayonSettings::INLINE_TAG_CAPTURE))) + ) { + self::init_tags_regex(); + // $the_content = preg_replace('#'.$ignore_flag_regex.'\s*([\[\{])\s*('. self::$alias_regex .')#', '$1$2', $the_content); + // $the_content = preg_replace('#('. self::$alias_regex .')\s*([\]\}])\s*'.$ignore_flag_regex.'#', '$1$2', $the_content); + $the_content = preg_replace('#' . $ignore_flag_regex . '(\s*[\[\{]\s*(' . self::$alias_regex . ')[^\]]*[\]\}])#', '$1', $the_content); + } + if (CrayonGlobalSettings::val(CrayonSettings::BACKQUOTE)) { + $the_content = str_ireplace('\\`', '`', $the_content); + } + return $the_content; + } + + public static function wp_head() { + CrayonLog::debug('head'); + + self::$wp_head = TRUE; + if (!self::$enqueued) { + CrayonLog::debug('head: missed enqueue'); + // We have missed our chance to check before enqueuing. Use setting to either load always or only in the_post + CrayonSettingsWP::load_settings(TRUE); // Ensure settings are loaded + // If we need the tag editor loaded at all times, we must enqueue at all times + if (!CrayonGlobalSettings::val(CrayonSettings::EFFICIENT_ENQUEUE) || CrayonGlobalSettings::val(CrayonSettings::TAG_EDITOR_FRONT)) { + CrayonLog::debug('head: force enqueue'); + // Efficient enqueuing disabled, always load despite enqueuing or not in the_post + self::enqueue_resources(); + } + } + // Enqueue Theme CSS + if (CrayonGlobalSettings::val(CrayonSettings::ENQUEUE_THEMES)) { + self::crayon_theme_css(); + } + // Enqueue Font CSS + if (CrayonGlobalSettings::val(CrayonSettings::ENQUEUE_FONTS)) { + self::crayon_font_css(); + } + } + + public static function save_post($update_id, $post) { + self::refresh_post($post); + } + + public static function filter_post_data($data, $postarr) { + // Remove the selected CSS that may be present from the tag editor. + CrayonTagEditorWP::init_settings(); + $css_selected = CrayonTagEditorWP::$settings['css_selected']; + $data['post_content'] = preg_replace("#(class\s*=\s*(\\\\[\"'])[^\"']*)$css_selected([^\"']*\\2)#msi", '$1$3', $data['post_content']); + return $data; + } + + public static function refresh_post($post, $refresh_legacy = TRUE, $save = TRUE) { + $postID = $post->ID; + if (wp_is_post_revision($postID)) { + // Ignore revisions + return; + } + if (CrayonWP::scan_post($post)) { + CrayonSettingsWP::add_post($postID, $save); + if ($refresh_legacy) { + if (self::scan_legacy_post($post)) { + CrayonSettingsWP::add_legacy_post($postID, $save); + } else { + CrayonSettingsWP::remove_legacy_post($postID, $save); + } + } + } else { + CrayonSettingsWP::remove_post($postID, $save); + CrayonSettingsWP::remove_legacy_post($postID, $save); + } + } + + public static function refresh_posts() { + CrayonSettingsWP::remove_posts(); + CrayonSettingsWP::remove_legacy_posts(); + foreach (CrayonWP::get_posts() as $post) { + self::refresh_post($post, TRUE, FALSE); + } + CrayonSettingsWP::save_posts(); + CrayonSettingsWP::save_legacy_posts(); + + } + + public static function save_comment($id, $is_spam = NULL, $comment = NULL) { + self::init_tags_regex(); + if ($comment === NULL) { + $comment = get_comment($id); + } + $content = $comment->comment_content; + $post_id = $comment->comment_post_ID; + $found = preg_match(self::$tags_regex, $content); + if ($found) { + CrayonSettingsWP::add_post($post_id); + } + return $found; + } + + public static function crayon_theme_css() { + global $CRAYON_VERSION; + CrayonSettingsWP::load_settings(); + $css = CrayonResources::themes()->get_used_css(); + foreach ($css as $theme => $url) { + wp_enqueue_style('crayon-theme-' . $theme, $url, array(), $CRAYON_VERSION); + } + } + + public static function crayon_font_css() { + global $CRAYON_VERSION; + CrayonSettingsWP::load_settings(); + $css = CrayonResources::fonts()->get_used_css(); + foreach ($css as $font_id => $url) { + wp_enqueue_style('crayon-font-' . $font_id, $url, array(), $CRAYON_VERSION); + } + } + + public static function init($request) { + CrayonLog::debug('init'); + crayon_load_plugin_textdomain(); + } + + public static function init_ajax() { + add_action('wp_ajax_crayon-tag-editor', 'CrayonTagEditorWP::content'); + add_action('wp_ajax_nopriv_crayon-tag-editor', 'CrayonTagEditorWP::content'); + add_action('wp_ajax_crayon-highlight', 'CrayonWP::ajax_highlight'); + add_action('wp_ajax_nopriv_crayon-highlight', 'CrayonWP::ajax_highlight'); + if (current_user_can('manage_options')) { + add_action('wp_ajax_crayon-ajax', 'CrayonWP::ajax'); + add_action('wp_ajax_crayon-theme-editor', 'CrayonThemeEditorWP::content'); + add_action('wp_ajax_crayon-theme-editor-save', 'CrayonThemeEditorWP::save'); + add_action('wp_ajax_crayon-theme-editor-delete', 'CrayonThemeEditorWP::delete'); + add_action('wp_ajax_crayon-theme-editor-duplicate', 'CrayonThemeEditorWP::duplicate'); + add_action('wp_ajax_crayon-theme-editor-submit', 'CrayonThemeEditorWP::submit'); + add_action('wp_ajax_crayon-show-posts', 'CrayonSettingsWP::show_posts'); + add_action('wp_ajax_crayon-show-langs', 'CrayonSettingsWP::show_langs'); + add_action('wp_ajax_crayon-show-preview', 'CrayonSettingsWP::show_preview'); + } + } + + public static function ajax() { + $allowed = array(CrayonSettings::HIDE_HELP); + foreach ($allowed as $allow) { + if (array_key_exists($allow, $_GET)) { + CrayonGlobalSettings::set($allow, $_GET[$allow]); + CrayonSettingsWP::save_settings(); + } + } + } + + public static function get_posts() { + $query = new WP_Query(array('post_type' => 'any', 'suppress_filters' => TRUE, 'posts_per_page' => '-1')); + if (isset($query->posts)) { + return $query->posts; + } else { + return array(); + } + } + + /** + * Return an array of post IDs where crayons occur. + * Comments are ignored by default. + */ + public static function scan_posts($check_comments = FALSE) { + $crayon_posts = array(); + foreach (self::get_posts() as $post) { + if (self::scan_post($post)) { + $crayon_posts[] = $post->ID; + } + } + return $crayon_posts; + } + + public static function scan_legacy_posts($init_regex = TRUE, $check_comments = FALSE) { + if ($init_regex) { + // We can skip this if needed + self::init_tags_regex(); + } + $crayon_posts = array(); + foreach (self::get_posts() as $post) { + if (self::scan_legacy_post($post)) { // TODO this part is different + $crayon_posts[] = $post->ID; + } + } + return $crayon_posts; + } + + /** + * Returns TRUE if a given post contains a Crayon tag + */ + public static function scan_post($post, $scan_comments = TRUE, $flags = NULL) { + if ($flags === NULL) { + self::init_tags_regex(TRUE); + } + + $id = $post->ID; + + $args = array( + 'ignore' => FALSE, + 'flags' => $flags, + 'skip_setting_check' => TRUE, + 'just_check' => TRUE + ); + $captures = self::capture_crayons($id, $post->post_content, array(), $args); + + if ($captures['has_captured']) { + return TRUE; + } else if ($scan_comments) { + CrayonSettingsWP::load_settings(TRUE); + if (CrayonGlobalSettings::val(CrayonSettings::COMMENTS)) { + $comments = get_comments(array('post_id' => $id)); + foreach ($comments as $comment) { + if (self::scan_comment($comment, $flags)) { + return TRUE; + } + } + } + } + return FALSE; + } + + public static function scan_legacy_post($post, $scan_comments = TRUE) { + self::init_legacy_tag_bits(); + return self::scan_post($post, $scan_comments, self::$legacy_flags); + } + + /** + * Returns TRUE if the comment contains a Crayon tag + */ + public static function scan_comment($comment, $flags = NULL) { + if ($flags === NULL) { + self::init_tags_regex(); + } + $args = array( + 'ignore' => FALSE, + 'flags' => $flags, + 'skip_setting_check' => TRUE, + 'just_check' => TRUE + ); + $content = apply_filters('get_comment_text', $comment->comment_content, $comment); + $captures = self::capture_crayons($comment->comment_ID, $content, array(), $args); + return $captures['has_captured']; + } + + public static function install() { + self::refresh_posts(); + self::update(); + } + + public static function uninstall() { + + } + + public static function update() { + global $CRAYON_VERSION; + CrayonSettingsWP::load_settings(TRUE); + $settings = CrayonSettingsWP::get_settings(); + if ($settings === NULL || !isset($settings[CrayonSettings::VERSION])) { + return; + } + + $version = $settings[CrayonSettings::VERSION]; + + // Only upgrade if the version differs + if ($version != $CRAYON_VERSION) { + $defaults = CrayonSettings::get_defaults_array(); + $touched = FALSE; + + // Upgrade database and settings + + if (CrayonUtil::version_compare($version, '1.7.21') < 0) { + $settings[CrayonSettings::SCROLL] = $defaults[CrayonSettings::SCROLL]; + $touched = TRUE; + } + + if (CrayonUtil::version_compare($version, '1.7.23') < 0 && $settings[CrayonSettings::FONT] == 'theme-font') { + $settings[CrayonSettings::FONT] = $defaults[CrayonSettings::FONT]; + $touched = TRUE; + } + + if (CrayonUtil::version_compare($version, '1.14') < 0) { + CrayonLog::syslog("Updated to v1.14: Font size enabled"); + $settings[CrayonSettings::FONT_SIZE_ENABLE] = TRUE; + } + + if (CrayonUtil::version_compare($version, '1.17') < 0) { + $settings[CrayonSettings::HIDE_HELP] = FALSE; + } + + // Save new version + $settings[CrayonSettings::VERSION] = $CRAYON_VERSION; + CrayonSettingsWP::save_settings($settings); + CrayonLog::syslog("Updated from $version to $CRAYON_VERSION"); + + // Refresh to show new settings + header('Location: ' . CrayonUtil::current_url()); + exit(); + } + } + + public static function basename() { + return plugin_basename(__FILE__); + } + + public static function pre_excerpt($e) { + CrayonLog::debug('pre_excerpt'); + self::$is_excerpt = TRUE; + return $e; + } + + public static function post_excerpt($e) { + CrayonLog::debug('post_excerpt'); + self::$is_excerpt = FALSE; + $e = self::the_content($e); + return $e; + } + + public static function post_get_excerpt($e) { + CrayonLog::debug('post_get_excerpt'); + self::$is_excerpt = FALSE; + return $e; + } + + /** + * Converts Crayon tags found in WP to
 form.
+     * XXX: This will alter blog content, so backup before calling.
+     * XXX: Do NOT call this while updating posts or comments, it may cause an infinite loop or fail.
+     * @param $encode Whether to detect missing "decode" attribute and encode html entities in the code.
+     */
+    public static function convert_tags($encode = FALSE) {
+        $crayon_posts = CrayonSettingsWP::load_legacy_posts();
+        if ($crayon_posts === NULL) {
+            return;
+        }
+
+        self::init_legacy_tag_bits();
+        $args = array(
+            'callback' => 'CrayonWP::capture_replace_pre',
+            'callback_extra_args' => array('encode' => $encode),
+            'ignore' => FALSE,
+            'preserve_atts' => TRUE,
+            'flags' => self::$legacy_flags,
+            'skip_setting_check' => TRUE
+        );
+
+        foreach ($crayon_posts as $postID) {
+            $post = get_post($postID);
+            $post_content = $post->post_content;
+            $post_captures = self::capture_crayons($postID, $post_content, array(), $args);
+
+            if ($post_captures['has_captured'] === TRUE) {
+                $post_obj = array();
+                $post_obj['ID'] = $postID;
+                $post_obj['post_content'] = addslashes($post_captures['content']);
+                wp_update_post($post_obj);
+                CrayonLog::syslog("Converted Crayons in post ID $postID to pre tags", 'CONVERT');
+            }
+
+            if (CrayonGlobalSettings::val(CrayonSettings::COMMENTS)) {
+                $comments = get_comments(array('post_id' => $postID));
+                foreach ($comments as $comment) {
+                    $commentID = $comment->comment_ID;
+                    $comment_captures = self::capture_crayons($commentID, $comment->comment_content, array(CrayonSettings::DECODE => TRUE), $args);
+
+                    if ($comment_captures['has_captured'] === TRUE) {
+                        $comment_obj = array();
+                        $comment_obj['comment_ID'] = $commentID;
+                        $comment_obj['comment_content'] = $comment_captures['content'];
+                        wp_update_comment($comment_obj);
+                        CrayonLog::syslog("Converted Crayons in post ID $postID, comment ID $commentID to pre tags", 'CONVERT');
+                    }
+                }
+            }
+        }
+
+        self::refresh_posts();
+    }
+
+    // Used as capture_crayons callback
+    public static function capture_replace_pre($capture, $original, $id, $is_inline, $wp_content, $args = array()) {
+        $code = $capture['code'];
+        $oldAtts = $capture['atts'];
+        $newAtts = array();
+        $encode = isset($args['encode']) ? $args['encode'] : FALSE;
+        if (!isset($oldAtts[CrayonSettings::DECODE]) && $encode) {
+            // Encode the content, since no decode information exists.
+            $code = CrayonUtil::htmlentities($code);
+        }
+        // We always set decode=1 irrespectively - so at this point the code is assumed to be encoded
+        $oldAtts[CrayonSettings::DECODE] = TRUE;
+        $newAtts['class'] = CrayonUtil::html_attributes($oldAtts, CrayonGlobalSettings::val_str(CrayonSettings::ATTR_SEP), '');
+        return str_replace($original, CrayonUtil::html_element('pre', $code, $newAtts), $wp_content);
+    }
+
+    // Add TinyMCE to comments
+    public static function tinymce_comment_enable($args) {
+        if (function_exists('wp_editor')) {
+            ob_start();
+            wp_editor('', 'comment', array('tinymce'));
+            $args['comment_field'] = ob_get_clean();
+        }
+        return $args;
+    }
+
+    public static function allowed_tags() {
+        global $allowedtags;
+        $tags = array('pre', 'span', 'code');
+        foreach ($tags as $tag) {
+            $current_atts = isset($allowedtags[$tag]) ? $allowedtags[$tag] : array();
+            // TODO data-url isn't recognised by WP
+            $new_atts = array('class' => TRUE, 'title' => TRUE, 'data-url' => TRUE);
+            $allowedtags[$tag] = array_merge($current_atts, $new_atts);
+        }
+    }
+
+}
+
+// Only if WP is loaded
+if (defined('ABSPATH')) {
+    if (!is_admin()) {
+        // Filters and Actions
+
+        add_filter('init', 'CrayonWP::init');
+
+        CrayonSettingsWP::load_settings(TRUE);
+        if (CrayonGlobalSettings::val(CrayonSettings::MAIN_QUERY)) {
+            add_action('wp', 'CrayonWP::wp', 100);
+        } else {
+            add_filter('the_posts', 'CrayonWP::the_posts', 100);
+        }
+
+        // XXX Some themes like to play with the content, make sure we replace after they're done
+        add_filter('the_content', 'CrayonWP::the_content', 100);
+
+        // Highlight bbPress content
+        add_filter('bbp_get_reply_content', 'CrayonWP::highlight', 100);
+        add_filter('bbp_get_topic_content', 'CrayonWP::highlight', 100);
+        add_filter('bbp_get_forum_content', 'CrayonWP::highlight', 100);
+        add_filter('bbp_get_topic_excerpt', 'CrayonWP::highlight', 100);
+
+        // Allow tags
+        add_action('init', 'CrayonWP::allowed_tags', 11);
+
+        if (CrayonGlobalSettings::val(CrayonSettings::COMMENTS)) {
+            /* XXX This is called first to match Crayons, then higher priority replaces after other filters.
+             Prevents Crayon from being formatted by the filters, and also keeps original comment formatting. */
+            add_filter('comment_text', 'CrayonWP::pre_comment_text', 1);
+            add_filter('comment_text', 'CrayonWP::comment_text', 100);
+        }
+
+        // This ensures Crayons are not formatted by WP filters. Other plugins should specify priorities between 1 and 100.
+        add_filter('get_the_excerpt', 'CrayonWP::pre_excerpt', 1);
+        add_filter('get_the_excerpt', 'CrayonWP::post_get_excerpt', 100);
+        add_filter('the_excerpt', 'CrayonWP::post_excerpt', 100);
+
+        add_action('template_redirect', 'CrayonWP::wp_head', 0);
+
+        if (CrayonGlobalSettings::val(CrayonSettings::TAG_EDITOR_FRONT)) {
+            add_filter('comment_form_defaults', 'CrayonWP::tinymce_comment_enable');
+        }
+    } else {
+        // Update between versions
+        CrayonWP::update();
+        // For marking a post as containing a Crayon
+        add_action('update_post', 'CrayonWP::save_post', 10, 2);
+        add_action('save_post', 'CrayonWP::save_post', 10, 2);
+        add_filter('wp_insert_post_data', 'CrayonWP::filter_post_data', '99', 2);
+    }
+    register_activation_hook(__FILE__, 'CrayonWP::install');
+    register_deactivation_hook(__FILE__, 'CrayonWP::uninstall');
+    if (CrayonGlobalSettings::val(CrayonSettings::COMMENTS)) {
+        add_action('comment_post', 'CrayonWP::save_comment', 10, 2);
+        add_action('edit_comment', 'CrayonWP::save_comment', 10, 2);
+    }
+    add_filter('init', 'CrayonWP::init_ajax');
+}
+
+?>
diff --git a/css/images/crayon_logo.png b/css/images/crayon_logo.png
new file mode 100644
index 0000000..8988332
Binary files /dev/null and b/css/images/crayon_logo.png differ
diff --git a/css/images/crayon_logo_square.png b/css/images/crayon_logo_square.png
new file mode 100644
index 0000000..7d5c7e2
Binary files /dev/null and b/css/images/crayon_logo_square.png differ
diff --git a/css/images/crayon_tinymce.png b/css/images/crayon_tinymce.png
new file mode 100644
index 0000000..c885955
Binary files /dev/null and b/css/images/crayon_tinymce.png differ
diff --git a/css/images/docs.png b/css/images/docs.png
new file mode 100644
index 0000000..eee67bc
Binary files /dev/null and b/css/images/docs.png differ
diff --git a/css/images/donate.png b/css/images/donate.png
new file mode 100644
index 0000000..0e6a0b9
Binary files /dev/null and b/css/images/donate.png differ
diff --git a/css/images/facebook.png b/css/images/facebook.png
new file mode 100644
index 0000000..fe3fce0
Binary files /dev/null and b/css/images/facebook.png differ
diff --git a/css/images/github.png b/css/images/github.png
new file mode 100644
index 0000000..81350e4
Binary files /dev/null and b/css/images/github.png differ
diff --git a/css/images/google.png b/css/images/google.png
new file mode 100644
index 0000000..780ac3e
Binary files /dev/null and b/css/images/google.png differ
diff --git a/css/images/theme_editor.png b/css/images/theme_editor.png
new file mode 100644
index 0000000..6cc35c3
Binary files /dev/null and b/css/images/theme_editor.png differ
diff --git a/css/images/thumb_horizontal.png b/css/images/thumb_horizontal.png
new file mode 100644
index 0000000..bcec00e
Binary files /dev/null and b/css/images/thumb_horizontal.png differ
diff --git a/css/images/thumb_vertical.png b/css/images/thumb_vertical.png
new file mode 100644
index 0000000..4bd81e1
Binary files /dev/null and b/css/images/thumb_vertical.png differ
diff --git a/css/images/toolbar/buttons.png b/css/images/toolbar/buttons.png
new file mode 100644
index 0000000..3ae89bd
Binary files /dev/null and b/css/images/toolbar/buttons.png differ
diff --git a/css/images/toolbar/buttons@2x.png b/css/images/toolbar/buttons@2x.png
new file mode 100644
index 0000000..add892c
Binary files /dev/null and b/css/images/toolbar/buttons@2x.png differ
diff --git a/css/images/track_horizontal.png b/css/images/track_horizontal.png
new file mode 100644
index 0000000..6cc7ca9
Binary files /dev/null and b/css/images/track_horizontal.png differ
diff --git a/css/images/track_vertical.png b/css/images/track_vertical.png
new file mode 100644
index 0000000..77f90ce
Binary files /dev/null and b/css/images/track_vertical.png differ
diff --git a/css/images/twitter.png b/css/images/twitter.png
new file mode 100644
index 0000000..2cbb44a
Binary files /dev/null and b/css/images/twitter.png differ
diff --git a/css/images/wordpress-blue.png b/css/images/wordpress-blue.png
new file mode 100644
index 0000000..a6f3268
Binary files /dev/null and b/css/images/wordpress-blue.png differ
diff --git a/css/min/crayon.min.css b/css/min/crayon.min.css
new file mode 100644
index 0000000..1c2a3d3
--- /dev/null
+++ b/css/min/crayon.min.css
@@ -0,0 +1 @@
+#colorbox.crayon-colorbox,#cboxOverlay.crayon-colorbox,.crayon-colorbox #cboxWrapper{position:absolute;top:0;left:0;z-index:9999;overflow:hidden}#cboxOverlay.crayon-colorbox{position:fixed;width:100%;height:100%}.crayon-colorbox #cboxMiddleLeft,.crayon-colorbox #cboxBottomLeft{clear:left}.crayon-colorbox #cboxContent{position:relative}.crayon-colorbox #cboxLoadedContent{overflow:auto;-webkit-overflow-scrolling:touch}.crayon-colorbox #cboxTitle{display:none!important}.crayon-colorbox #cboxLoadingOverlay,.crayon-colorbox #cboxLoadingGraphic{position:absolute;top:0;left:0;width:100%;height:100%}.crayon-colorbox #cboxPrevious,.crayon-colorbox #cboxNext,.crayon-colorbox #cboxClose,.crayon-colorbox #cboxSlideshow{cursor:pointer}.crayon-colorbox .cboxPhoto{float:left;margin:auto;border:0;display:block;max-width:none;-ms-interpolation-mode:bicubic}.crayon-colorbox .cboxIframe{width:100%;height:100%;display:block;border:0}#colorbox.crayon-colorbox,.crayon-colorbox #cboxContent,.crayon-colorbox #cboxLoadedContent{box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box}#cboxOverlay.crayon-colorbox{background:#000}#colorbox.crayon-colorbox{outline:0}.crayon-colorbox #cboxContent{margin-top:20px;background:#000}.crayon-colorbox .cboxIframe{background:#fff}.crayon-colorbox #cboxError{padding:50px;border:1px solid #ccc}.crayon-colorbox #cboxLoadedContent{border:5px solid #000;background:#fff}.crayon-colorbox #cboxTitle{position:absolute;top:-20px;left:0;color:#ccc}.crayon-colorbox #cboxCurrent{position:absolute;top:-20px;right:0;color:#ccc}.crayon-colorbox #cboxPrevious,.crayon-colorbox #cboxNext,.crayon-colorbox #cboxSlideshow,.crayon-colorbox #cboxClose{border:0;padding:0;margin:0;overflow:visible;width:auto;background:0}.crayon-colorbox #cboxPrevious:active,.crayon-colorbox #cboxNext:active,.crayon-colorbox #cboxSlideshow:active,.crayon-colorbox #cboxClose:active{outline:0}.crayon-colorbox #cboxSlideshow{position:absolute;top:-20px;right:90px;color:#fff}.crayon-colorbox #cboxContent{margin-top:0}.crayon-colorbox #cboxLoadedContent{border:0}#crayon-main-wrap .form-table th{width:100px}#crayon-log{display:none;max-height:200px;border-color:#dfdfdf;background-color:white;border-width:1px;border-style:solid;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;margin:1px;padding:3px;overflow:auto;white-space:pre;margin-bottom:5px}.crayon-span,.crayon-span-5,.crayon-span-10,.crayon-span-50,.crayon-span-100,.crayon-span-110{line-height:24px;display:inline-block}.crayon-span-5{min-width:5px}.crayon-span-10{min-width:10px}.crayon-span-50{min-width:50px}.crayon-span-100{min-width:100px}.crayon-span-110{min-width:117px}.crayon-span-margin{margin-left:5px}#height_mode,#width_mode{min-width:65px}.crayon-error{color:#F00}.crayon-success{color:#00F}.crayon-warning{color:#ff8000}.crayon-help{min-height:30px;padding:5px 10px}.crayon-help .crayon-help-close,.crayon-help .crayon-help-close:active,.crayon-help .crayon-help-close:hover{text-decoration:none;float:right;color:#000}.crayon-help span,.crayon-help a{margin:0;padding:0;font-size:12px}#crayon-log-text{font:11px/13px Monaco,'MonacoRegular','Courier New',monospace}#crayon-log-controls{float:left;margin-right:5px}.crayon-table{font-size:12px;border:1px solid #999;padding:0;margin:0;margin-top:12px}.crayon-table td{vertical-align:top;border-bottom:1px solid #AAA;padding:0 6px;margin:0;background:#EEE}.crayon-table-light td{background:#f8f8f8}.crayon-table-header td{font-weight:bold;background:#CCC}.crayon-table-last td,.crayon-table tr:last-child td{border:0}#lang-info div{padding:5px 0}.crayon-table .not-parsed{color:#F00}.crayon-table .parsed-with-errors{color:#f90}.crayon-table .successfully-parsed{color:#77a000}#crayon-live-preview,#crayon-log-wrapper{padding:0;width:100%;float:left;clear:both}#crayon-live-preview{float:none;padding:0}#crayon-logo{text-align:center}#crayon-info,#crayon-info td{border:0;padding:0 5px;margin:0}.crayon-admin-button{display:inline-block;text-align:center}#crayon-subsection-langs-info{margin-top:5px}#crayon-theme-editor-admin-buttons{display:inline}#crayon-theme-editor-admin-buttons .crayon-admin-button{margin-left:5px}#crayon-theme-info{display:table;padding:0;margin:0;margin-top:5px}#crayon-theme-info>div{display:table-cell;vertical-align:middle}#crayon-theme-info .content *{float:left}#crayon-theme-info .field{font-weight:bold}#crayon-theme-info .field,#crayon-theme-info .value{margin-left:5px}#crayon-theme-info .description.value{font-style:italic;color:#999}#crayon-theme-info .type{text-align:center;min-width:120px;font-weight:bold;border-right:1px solid #ccc;padding-right:5px}#crayon-theme-info .type.stock{color:#666}#crayon-theme-info .type.user{color:#5b9a00}#crayon-editor-table td{vertical-align:top}.small-icon{width:24px;height:24px;display:inline-block;margin:5px 5px 0 0}#twitter-icon{background:url(../images/twitter.png)}#gmail-icon{background:url(../images/google.png)}#docs-icon{background:url(../images/docs.png)}#git-icon{background:url(../images/github.png)}#wp-icon{background:url(../images/wordpress-blue.png)}#donate-icon{background:url(../images/donate.png);width:75px}#crayon-donate,#crayon-donate input{margin:0;display:inline;padding:0}#crayon-theme-editor-info a{text-decoration:none!important;font-style:italic!important;color:#666!important}#crayon-main-wrap .form-table .note{font-style:italic;color:#999}#crayon-change-code-text{width:400px;height:300px}.crayon-syntax{overflow:hidden!important;position:relative!important;direction:ltr;text-align:left;box-sizing:border-box;direction:ltr!important;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-text-size-adjust:none}.crayon-syntax div{background:0;border:0;padding:0;margin:0;text-align:left}.crayon-syntax.crayon-loading{visibility:hidden}.crayon-syntax,.crayon-syntax .crayon-main,.crayon-syntax .crayon-toolbar,.crayon-syntax .crayon-info,.crayon-syntax .crayon-plain,.crayon-syntax .crayon-code{width:100%}.crayon-syntax .crayon-main,.crayon-syntax .crayon-plain{overflow:auto}.crayon-syntax,.crayon-syntax .crayon-main,.crayon-syntax .crayon-plain,.crayon-syntax .crayon-table{padding:0;margin:0}.crayon-syntax-inline{margin:0 2px;padding:0 2px}.crayon-syntax .crayon-table{border:none!important;background:none!important;padding:0!important;margin-top:0!important;margin-right:0!important;margin-bottom:0!important;width:auto!important;border-spacing:0!important;border-collapse:collapse!important;table-layout:auto!important}.crayon-syntax .crayon-table td,.crayon-syntax .crayon-table tr{padding:0!important;border:none!important;background:0;vertical-align:top!important;margin:0!important}.crayon-syntax .crayon-invisible{display:none!important}.crayon-plain-tag{margin-bottom:12px}.crayon-popup .crayon-plain{display:block!important;width:100%!important;height:100%!important;opacity:100!important;position:relative!important}.crayon-popup-window{background:#fff}.crayon-syntax .crayon-num{text-align:center;padding:0 5px;margin:0}.crayon-syntax .crayon-toolbar{position:relative;overflow:hidden;z-index:4}.crayon-syntax .crayon-info{position:absolute;overflow:hidden;display:none;z-index:3;padding:0;min-height:18px;line-height:18px}.crayon-syntax .crayon-info div{padding:2px!important;text-align:center}.crayon-syntax .crayon-toolbar span{padding:0 4px!important}.crayon-syntax .crayon-toolbar .crayon-button{display:inline;float:left!important;position:relative;width:24px;background-repeat:no-repeat;line-height:15px;border:0;text-decoration:none}.crayon-toolbar .crayon-button,.crayon-toolbar .crayon-button:hover,.crayon-toolbar .crayon-button.crayon-pressed:hover{background-position:0 center}.crayon-toolbar .crayon-button.crayon-pressed,.crayon-toolbar .crayon-button:active,.crayon-toolbar .crayon-button.crayon-pressed:active{background-position:-24px 0}.crayon-toolbar .crayon-button.crayon-popup-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:hover .crayon-button-icon{background-position:0 0}.crayon-toolbar .crayon-button.crayon-copy-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -16px}.crayon-toolbar .crayon-button.crayon-nums-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -32px}.crayon-toolbar .crayon-button.crayon-plain-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -48px}.crayon-toolbar .crayon-button.crayon-mixed-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -64px}.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon{background-position:0 -80px;background-color:transparent!important}.crayon-toolbar .crayon-button.crayon-expand-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -96px}.crayon-toolbar .crayon-button.crayon-wrap-button .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button:hover .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:hover .crayon-button-icon{background-position:0 -112px}.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:active .crayon-button-icon{background-position:-24px 0}.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -16px}.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -32px}.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -48px}.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -64px}.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon{background-position:-24px -80px;background-color:transparent!important}.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -96px}.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button:active .crayon-button-icon,.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:active .crayon-button-icon{background-position:-24px -112px}.crayon-syntax .crayon-toolbar .crayon-language{padding-right:8px!important}.crayon-syntax .crayon-title,.crayon-syntax .crayon-language{float:left}.crayon-main::-webkit-scrollbar,.crayon-plain::-webkit-scrollbar{height:6px;overflow:visible;width:6px;background:#EEE}.crayon-main::-webkit-scrollbar-thumb,.crayon-plain::-webkit-scrollbar-thumb{background-color:#CCC;background-clip:padding-box;border:1px solid #AAA;box-shadow:inset 0 0 2px #999;min-height:8px;padding:0;border-width:1px}.crayon-main::-webkit-scrollbar-button,.crayon-plain::-webkit-scrollbar-button{height:0;width:0;padding:0}.crayon-main::-webkit-scrollbar-track,.crayon-plain::-webkit-scrollbar-track{background-clip:padding-box;border:solid transparent;border-width:0 0 0 4px;border:1px solid #BBB;border-right:0;border-bottom:0}.crayon-main::-webkit-scrollbar-corner,.crayon-plain::-webkit-scrollbar-corner{background:#EEE}.crayon-main::-webkit-scrollbar-thumb:hover,.crayon-plain::-webkit-scrollbar-thumb:hover{background:#AAA;border:1px solid #777;box-shadow:inset 0 0 2px #777}.crayon-syntax .crayon-pre,.crayon-syntax pre{color:#000;white-space:pre;margin:0;padding:0;overflow:visible;background:none!important;border:none!important;tab-size:4}.crayon-syntax .crayon-line{padding:0 5px}.crayon-syntax.crayon-wrapped .crayon-line{white-space:pre-wrap!important;height:auto;word-break:break-all}.crayon-syntax-inline .crayon-pre,.crayon-syntax-inline pre{white-space:normal}.crayon-syntax-inline-nowrap .crayon-pre,.crayon-syntax-inline-nowrap pre{white-space:pre}.crayon-syntax{font-family:Monaco,'MonacoRegular','Courier New',monospace;font-weight:500}.crayon-syntax .crayon-toolbar *::selection,.crayon-syntax .crayon-nums *::selection{background:transparent}.crayon-table .crayon-nums-content{white-space:nowrap}.crayon-syntax .crayon-num,.crayon-syntax .crayon-pre .crayon-line,.crayon-syntax .crayon-toolbar *,.crayon-syntax .crayon-pre *{font-family:inherit;font-size:inherit!important;line-height:inherit!important;font-weight:inherit!important;height:inherit}.crayon-syntax .crayon-toolbar .crayon-button .crayon-button-icon{background-image:url('../images/toolbar/buttons.png');height:16px!important;width:100%;position:absolute;left:0;top:50%;margin-top:-8px}.crayon-syntax .crayon-toolbar .crayon-tools{position:absolute;right:0}.crayon-syntax.crayon-expanded{position:absolute!important;margin:0!important}.crayon-syntax.crayon-expanded .crayon-main{overflow:hidden!important}.crayon-placeholder{width:100%!important}.crayon-toolbar-visible .crayon-toolbar{position:relative!important;margin-top:0!important;display:block!important}.crayon-syntax.crayon-expanded .crayon-toolbar .crayon-tools{position:relative;right:auto;float:left!important}.crayon-syntax .crayon-plain-wrap{height:auto!important;padding:0!important;margin:0!important}.crayon-syntax .crayon-plain{width:100%;height:100%;position:absolute;opacity:0;padding:0 5px;margin:0;border:0;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-shadow:none;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;white-space:pre;word-wrap:normal;overflow:auto;resize:none;color:#000;background:#FFF}.crayon-wrapped .crayon-plain{white-space:pre-wrap}.bbp-body .crayon-syntax{clear:none!important}.crayon-minimized .crayon-toolbar{cursor:pointer}.crayon-minimized .crayon-plain-wrap,.crayon-minimized .crayon-main,.crayon-minimized .crayon-toolbar .crayon-tools *{display:none!important}.crayon-minimized .crayon-toolbar .crayon-tools .crayon-minimize{display:block!important}.crayon-minimized .crayon-toolbar{position:relative!important}.crayon-syntax.crayon-minimized .crayon-toolbar{border-bottom:none!important}.crayon-te *,#crayon-te-bar-content{font-family:"Lucida Grande",Arial,sans-serif!important;font-size:12px}.crayon-te input[type="text"],.crayon-te textarea{background:#f9f9f9;border:1px solid #CCC;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);padding:2px 4px;-webkit-border-radius:3px;border-radius:3px;border-width:1px;border-style:solid}.crayon-te #crayon-code{font-family:monospace!important}#crayon-te-content,#crayon-te-table{width:100%;height:auto!important}#crayon-range,#crayon-mark{width:100px}#crayon-te-table th,#crayon-te-table td{vertical-align:top;text-align:left}.rtl #crayon-te-table th,.rtl #crayon-te-table td{text-align:right}#crayon-te-table .crayon-tr-center td,#crayon-te-table .crayon-tr-center th{vertical-align:middle}#crayon-te-table .crayon-nowrap{white-space:nowrap}#crayon-te-bar{position:absolute;top:0;left:0;width:100%}#crayon-te-bar-content{border:1px solid #666;border-bottom:0;height:26px;line-height:25px;padding:0 8px;padding-right:0;background-color:#222;color:#cfcfcf}#crayon-te-bar-content a{line-height:25px;padding:5px 10px;color:#DDD;font-weight:bold;text-decoration:none!important}#crayon-te-bar-content a:hover{color:#FFF}.crayon-te-seperator{color:#666;margin:0;padding:0}#crayon-te-bar-block{height:34px;width:100%}#crayon-te-title{float:left}#crayon-te-controls{float:right}#crayon-url-th{vertical-align:top!important;padding-top:5px}.crayon-te-heading{font-size:14px;font-weight:bold}#crayon-te-settings-info{text-align:center}.crayon-te-section{font-weight:bold;padding:0 10px}#crayon-te-sub-section{margin-left:10px}#crayon-te-sub-section .crayon-te-section{font-weight:normal;padding:0}#crayon-code{height:200px;white-space:pre}#crayon-code,#crayon-url{width:555px!important}.crayon-disabled{background:#EEE!important}.qt_crayon_highlight{background-image:-ms-linear-gradient(bottom,#daf2ff,white)!important;background-image:-moz-linear-gradient(bottom,#daf2ff,white)!important;background-image:-o-linear-gradient(bottom,#daf2ff,white)!important;background-image:-webkit-linear-gradient(bottom,#daf2ff,white)!important;background-image:linear-gradient(bottom,#daf2ff,white)!important}.qt_crayon_highlight:hover{background:#ddebf2!important}.crayon-tag-editor-button-wrapper{display:inline-block}.mce_crayon_tinymce{padding:0!important;margin:2px 3px!important}.mce-i-crayon_tinymce,.mce_crayon_tinymce{background:url(../images/crayon_tinymce.png) 0 0!important}a.mce_crayon_tinymce{background-position:2px 0!important}.wp_themeSkin .mceButtonEnabled:hover span.mce_crayon_tinymce,.wp_themeSkin .mceButtonActive span.mce_crayon_tinymce{background-position:-20px 0}.wp_themeSkin span.mce_crayon_tinymce{background:none!important}#crayon-te-table{margin-top:26px;padding:10px;border-collapse:separate!important;border-spacing:2px!important}#crayon-te-table th{width:100px}#crayon-te-clear{margin-left:10px;color:#666;background-color:#f4f4f4;border:1px solid #CCC;border-radius:3px;margin-left:8px}#crayon-title{width:360px}#TB_window.crayon-te-ajax{overflow:auto!important}#TB_window.crayon-te-ajax,#TB_window.crayon-te-ajax #TB_ajaxContent,#TB_window.crayon-te-ajax #TB_title{width:680px!important}#TB_window.crayon-te-ajax #TB_ajaxContent{padding:0!important;margin:0!important;width:100%!important;height:auto!important;margin-top:28px!important}#TB_window.crayon-te-ajax #TB_title{position:fixed!important}#TB_window.crayon-te-ajax #TB_title .crayon-te-submit{margin-top:3px!important;float:right!important}#TB_window.crayon-te-ajax a{color:#2587e2;text-decoration:none}#TB_window.crayon-te-ajax a:hover{color:#499ce9}.crayon-te-quote{background:#DDD;padding:0 2px}#crayon-te-submit-wrapper{display:none}#crayon-te-clear{display:none;margin:0;margin-top:10px}.crayon-syntax-pre{background:red;white-space:pre;overflow:auto;display:block;word-wrap:break-word}.crayon-question{padding:1px 4px!important;text-decoration:none!important;color:#83b3cb!important;border-radius:10px!important;height:15px!important;width:15px!important}.crayon-question:hover{background:#83b3cb!important;color:white!important;height:15px!important;width:15px!important}.crayon-setting-changed,.crayon-setting-selected{background:#fffaad!important}.crayon-question:hover{color:white;background:#a6d6ef}#crayon-te-warning{display:none}.crayon-te-info{padding:5px!important;margin:2px 0!important}#crayon-te-submit{margin-bottom:5px}
\ No newline at end of file
diff --git a/css/minify.sh b/css/minify.sh
new file mode 100644
index 0000000..dcfd149
--- /dev/null
+++ b/css/minify.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+BASEDIR=$(dirname $0)
+cd $BASEDIR
+
+source ../util/minify.sh
+
+minify $COLORBOX_PATH/colorbox.css $INPUT_PATH/admin_style.css $INPUT_PATH/crayon_style.css $INPUT_PATH/global_style.css $OUTPUT_PATH/crayon.min.css
diff --git a/css/src/admin_style.css b/css/src/admin_style.css
new file mode 100644
index 0000000..95050aa
--- /dev/null
+++ b/css/src/admin_style.css
@@ -0,0 +1,285 @@
+#crayon-log-wrapper {
+	/*width: 100%;*/
+}
+
+#crayon-main-wrap .form-table th {
+	width: 100px;
+}
+
+#crayon-log {
+	display: none;
+	max-height: 200px;
+	/*width: 100%;
+    /*resize: vertical;*/
+	border-color: #DFDFDF;
+	background-color: white;
+	border-width: 1px;
+	border-style: solid;
+	border-radius: 4px;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	margin: 1px;
+	padding: 3px;
+	overflow: auto;
+	white-space: pre;
+	margin-bottom: 5px;
+}
+
+.crayon-span,.crayon-span-5,.crayon-span-10,.crayon-span-50,.crayon-span-100,.crayon-span-110 {
+	line-height: 24px;
+	display: inline-block;
+}
+
+.crayon-span-5 {
+	min-width: 5px;
+}
+
+.crayon-span-10 {
+	min-width: 10px;
+}
+
+.crayon-span-50 {
+	min-width: 50px;
+}
+
+.crayon-span-100 {
+	min-width: 100px;
+}
+
+.crayon-span-110 {
+	min-width: 117px;
+}
+
+.crayon-span-margin {
+	margin-left: 5px;
+}
+
+#height_mode, #width_mode {
+	min-width: 65px;
+}
+
+.crayon-error {
+	color: #F00;
+}
+
+.crayon-success {
+	color: #00F;
+}
+
+.crayon-warning {
+	color: #FF8000;
+}
+
+.crayon-help {
+	min-height: 30px;
+	padding: 5px 10px;
+}
+
+.crayon-help .crayon-help-close,
+.crayon-help .crayon-help-close:active,
+.crayon-help .crayon-help-close:hover {
+	text-decoration: none;
+	float: right;
+	color: #000;
+}
+
+.crayon-help span,
+.crayon-help a {
+	margin: 0;
+	padding: 0;
+	font-size: 12px;
+}
+
+#crayon-log-text {
+	font: 11px/13px Monaco, 'MonacoRegular', 'Courier New', monospace;
+}
+
+#crayon-log-controls {
+	float: left;
+	margin-right: 5px;
+	/*margin: 5px 0px;*/
+}
+
+.crayon-table {
+	font-size: 12px;
+	border: 1px solid #999;
+	padding: 0;
+	margin: 0;
+	margin-top: 12px;
+}
+
+.crayon-table td {
+	vertical-align: top;
+	border-bottom: 1px solid #AAA;
+	padding: 0px 6px;
+	margin: 0;
+	background: #EEE;
+}
+
+.crayon-table-light td {
+	background: #F8F8F8;
+}
+
+.crayon-table-header td {
+	font-weight: bold;
+	background: #CCC;
+}
+
+.crayon-table-last td,
+.crayon-table tr:last-child td {
+	border: 0;
+}
+
+/*#lang-info {
+	display: none;
+}*/
+
+#lang-info div {
+	padding: 5px 0px;
+}
+
+.crayon-table .not-parsed {
+	color: #F00;
+}
+
+.crayon-table .parsed-with-errors {
+	color: #FF9900;
+}
+
+.crayon-table .successfully-parsed {
+	color: #77A000;
+}
+
+#crayon-live-preview,
+#crayon-log-wrapper {
+	padding: 0px;
+	width: 100%;
+	float: left;
+	clear: both;
+}
+
+#crayon-live-preview {
+	float: none;
+	padding: 0;
+}
+
+#crayon-logo {
+	text-align: center;
+}
+
+#crayon-info,
+#crayon-info td {
+	border: none;
+	padding: 0 5px;
+	margin: 0px;
+}
+
+.crayon-admin-button {
+	display: inline-block;
+	text-align: center;
+}
+
+#crayon-subsection-langs-info {
+	margin-top: 5px;
+}
+
+#crayon-theme-editor-admin-buttons {
+	display: inline;
+}
+
+#crayon-theme-editor-admin-buttons .crayon-admin-button {
+	margin-left: 5px;
+}
+
+#crayon-theme-info {
+    display: table;
+    padding: 0;
+    margin: 0;
+    margin-top: 5px;
+}
+#crayon-theme-info > div {
+    display: table-cell;
+    vertical-align: middle;
+}
+#crayon-theme-info .content * {
+    float: left;
+}
+#crayon-theme-info .field {
+	font-weight: bold;
+}
+#crayon-theme-info .field,
+#crayon-theme-info .value {
+	margin-left: 5px;
+}
+#crayon-theme-info .description.value {
+    font-style: italic;
+    color: #999;
+}
+#crayon-theme-info .type {
+    text-align: center;
+    min-width: 120px;
+    font-weight: bold;
+    border-right: 1px solid #ccc;
+    padding-right: 5px;
+}
+#crayon-theme-info .type.stock {
+    color: #666;
+}
+#crayon-theme-info .type.user {
+    color: #5b9a00;
+}
+
+#crayon-editor-table td {
+	vertical-align: top;
+}
+
+.small-icon {
+	width: 24px;
+	height: 24px;
+	display: inline-block;
+	margin: 5px 5px 0 0;
+}
+
+#twitter-icon {
+	background: url(../images/twitter.png);
+}
+#gmail-icon {
+	background: url(../images/google.png);
+}
+#docs-icon {
+	background: url(../images/docs.png);
+}
+#git-icon {
+	background: url(../images/github.png);
+}
+#wp-icon {
+	background: url(../images/wordpress-blue.png);
+}
+
+#donate-icon {
+	background: url(../images/donate.png);
+	width: 75px;
+}
+
+#crayon-donate,
+#crayon-donate input {
+	margin: 0;
+	display: inline;
+	padding: 0;
+}
+
+#crayon-theme-editor-info a {
+    text-decoration: none !important;
+    font-style: italic !important;
+    color: #666 !important;
+}
+
+#crayon-main-wrap .form-table .note {
+    font-style: italic;
+    color: #999;
+}
+
+#crayon-change-code-text {
+    width: 400px;
+    height: 300px;
+}
diff --git a/css/src/crayon_style.css b/css/src/crayon_style.css
new file mode 100644
index 0000000..cd09b55
--- /dev/null
+++ b/css/src/crayon_style.css
@@ -0,0 +1,530 @@
+/*
+Crayon Syntax Highlighter Structure Style Sheet
+
+- This style sheet is used to structure a Crayon's dimensions and visibility, but does not contain any details regarding
+coloring etc.
+- Attributes, where possible, are kept flexible such that Themes can customise them.
+- Themes are used to add coloring to the Crayon and the syntax highlighting itself.
+- Themes can be considered as layers on top of this style sheet.
+- Several attributes are marked !important where they are required to remain unchanged by CSS precedence,
+  which may occur from conflicts with certain Wordpress Themes.
+- The attributes in Themes are generally all marked !important to ensure styles are not altered by precedence.  
+*/
+
+/* General ========================= */
+.crayon-syntax {
+    overflow: hidden !important;
+    position: relative !important;
+    direction: ltr;
+    text-align: left;
+    box-sizing: border-box;
+    direction: ltr !important;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    -webkit-text-size-adjust: none;
+}
+
+.crayon-syntax div {
+    /* Need !important? */
+    background: none;
+    border: none;
+    padding: 0px;
+    margin: 0px;
+    text-align: left;
+}
+
+.crayon-syntax.crayon-loading {
+    visibility: hidden;
+}
+
+.crayon-syntax,
+.crayon-syntax .crayon-main,
+.crayon-syntax .crayon-toolbar,
+.crayon-syntax .crayon-info,
+.crayon-syntax .crayon-plain,
+.crayon-syntax .crayon-code {
+    /* Dimensions of code */
+    width: 100%;
+}
+
+.crayon-syntax .crayon-main,
+.crayon-syntax .crayon-plain {
+    /* TODO a bug in IE8 causes max-height and overflow:auto to set max-height = height
+       http://edskes.net/ie8overflowandexpandingboxbugs.htm */
+    overflow: auto;
+}
+
+.crayon-syntax,
+.crayon-syntax .crayon-main,
+.crayon-syntax .crayon-plain,
+.crayon-syntax .crayon-table {
+    padding: 0px;
+    margin: 0px;
+}
+
+.crayon-syntax-inline {
+    margin: 0 2px;
+    padding: 0 2px;
+}
+
+.crayon-syntax .crayon-table {
+    border: none !important;
+    background: none !important;
+    padding: 0px !important;
+    margin-top: 0px !important;
+    margin-right: 0px !important;
+    margin-bottom: 0px !important;
+    width: auto !important;
+    border-spacing: 0 !important;
+    border-collapse: collapse !important;
+    table-layout: auto !important;
+}
+
+.crayon-syntax .crayon-table td,
+.crayon-syntax .crayon-table tr {
+    padding: 0 !important;
+    border: none !important;
+    background: none;
+    vertical-align: top !important;
+    margin: 0 !important;
+}
+
+.crayon-syntax .crayon-invisible {
+    display: none !important;
+}
+
+.crayon-plain-tag {
+    margin-bottom: 12px;
+}
+
+/* End General ===================== */
+
+/* Popup ========================= */
+.crayon-popup {
+
+}
+
+.crayon-popup .crayon-plain {
+    display: block !important;
+    width: 100% !important;
+    height: 100% !important;
+    opacity: 100 !important;
+    position: relative !important;
+}
+
+.crayon-popup-window {
+    background: #fff;
+}
+
+/* End Popup ========================= */
+
+/* Line Numbers ==================== */
+.crayon-syntax .crayon-num {
+    text-align: center;
+    padding: 0 5px;
+    margin: 0px;
+}
+
+/* End Line Numbers ================ */
+
+/* Toolbar & Info ================== */
+.crayon-syntax .crayon-toolbar {
+    position: relative;
+    overflow: hidden;
+    z-index: 4;
+}
+
+.crayon-syntax .crayon-info {
+    position: absolute;
+    overflow: hidden;
+    display: none;
+    z-index: 3;
+    padding: 0px;
+    /* Must be able to expand! */
+    min-height: 18px;
+    line-height: 18px;
+}
+
+.crayon-syntax .crayon-info div {
+    padding: 2px !important;
+    text-align: center;
+}
+
+/*.crayon-syntax .crayon-toolbar,*/
+/*.crayon-syntax .crayon-toolbar * {*/
+/*height: 18px;*/
+/*line-height: 18px;*/
+/*padding: 0px;*/
+/*}*/
+
+.crayon-syntax .crayon-toolbar span {
+    padding: 0 4px !important;
+}
+
+.crayon-syntax .crayon-toolbar .crayon-button {
+    display: inline;
+    float: left !important;
+    position: relative;
+    width: 24px;
+    background-repeat: no-repeat;
+    /*height: 16px;*/
+    line-height: 15px;
+    /*padding: 0px 2px !important;*/
+    border: none;
+    /*border-radius: 5px;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;*/
+    text-decoration: none;
+}
+
+.crayon-toolbar .crayon-button,
+.crayon-toolbar .crayon-button:hover,
+.crayon-toolbar .crayon-button.crayon-pressed:hover {
+    background-position: 0px center;
+}
+
+.crayon-toolbar .crayon-button.crayon-pressed,
+.crayon-toolbar .crayon-button:active,
+.crayon-toolbar .crayon-button.crayon-pressed:active {
+    background-position: -24px 0;
+}
+
+.crayon-toolbar .crayon-button.crayon-popup-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-popup-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 0;
+}
+
+.crayon-toolbar .crayon-button.crayon-copy-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-copy-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -16px;
+}
+
+.crayon-toolbar .crayon-button.crayon-nums-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-nums-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -32px;
+}
+
+.crayon-toolbar .crayon-button.crayon-plain-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-plain-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -48px;
+}
+
+.crayon-toolbar .crayon-button.crayon-mixed-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-mixed-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -64px;
+}
+
+.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon {
+    background-position: 0 -80px;
+    background-color: transparent !important;
+}
+
+.crayon-toolbar .crayon-button.crayon-expand-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-expand-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -96px;
+}
+
+.crayon-toolbar .crayon-button.crayon-wrap-button .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-wrap-button:hover .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:hover .crayon-button-icon {
+    background-position: 0 -112px;
+}
+
+/* -- */
+
+.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-popup-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-popup-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px 0;
+}
+
+.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-copy-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-copy-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -16px;
+}
+
+.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-nums-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-nums-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -32px;
+}
+
+.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-plain-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-plain-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -48px;
+}
+
+.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-mixed-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-mixed-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -64px;
+}
+
+.crayon-toolbar .crayon-button.crayon-minimize .crayon-button-icon {
+    background-position: -24px -80px;
+    background-color: transparent !important;
+}
+
+.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-expand-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-expand-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -96px;
+}
+
+.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-wrap-button:active .crayon-button-icon,
+.crayon-toolbar .crayon-button.crayon-wrap-button.crayon-pressed:active .crayon-button-icon {
+    background-position: -24px -112px;
+}
+
+/* Language */
+.crayon-syntax .crayon-toolbar .crayon-language {
+    padding-right: 8px !important;
+}
+
+.crayon-syntax .crayon-title,
+.crayon-syntax .crayon-language {
+    float: left;
+}
+
+/* End Toolbar ===================== */
+
+/* Scrollbar ======================= */
+.crayon-main::-webkit-scrollbar,
+.crayon-plain::-webkit-scrollbar {
+    height: 6px;
+    overflow: visible;
+    width: 6px;
+    background: #EEE;
+}
+
+.crayon-main::-webkit-scrollbar-thumb,
+.crayon-plain::-webkit-scrollbar-thumb {
+    background-color: #CCC;
+    background-clip: padding-box;
+    border: 1px solid #AAA;
+    box-shadow: inset 0 0 2px #999;
+    min-height: 8px;
+    padding: 0;
+    border-width: 1px;
+}
+
+.crayon-main::-webkit-scrollbar-button,
+.crayon-plain::-webkit-scrollbar-button {
+    height: 0;
+    width: 0;
+    padding: 0px;
+}
+
+.crayon-main::-webkit-scrollbar-track,
+.crayon-plain::-webkit-scrollbar-track {
+    background-clip: padding-box;
+    border: solid transparent;
+    border-width: 0 0 0 4px;
+    border: 1px solid #BBB;
+    border-right: none;
+    border-bottom: none;
+}
+
+.crayon-main::-webkit-scrollbar-corner,
+.crayon-plain::-webkit-scrollbar-corner {
+    background: #EEE;
+}
+
+.crayon-main::-webkit-scrollbar-thumb:hover,
+.crayon-plain::-webkit-scrollbar-thumb:hover {
+    background: #AAA;
+    border: 1px solid #777;
+    box-shadow: inset 0 0 2px #777;
+}
+
+/* End Scrollbar =================== */
+
+/* Code ============================ */
+.crayon-syntax .crayon-pre,
+.crayon-syntax pre {
+    color: #000;
+    white-space: pre;
+    margin: 0;
+    padding: 0;
+    overflow: visible;
+    background: none !important;
+    border: none !important;
+    tab-size: 4;
+}
+
+.crayon-syntax .crayon-line {
+    padding: 0 5px;
+}
+
+.crayon-syntax.crayon-wrapped .crayon-line {
+    /* width: 500px !important; */
+    white-space: pre-wrap !important;
+    /*    word-wrap:break-word !important;*/
+    height: auto;
+    word-break: break-all;
+}
+
+.crayon-syntax-inline .crayon-pre,
+.crayon-syntax-inline pre {
+    white-space: normal;
+}
+
+.crayon-syntax-inline-nowrap .crayon-pre,
+.crayon-syntax-inline-nowrap pre {
+    white-space: pre;
+}
+
+/* Default Font */
+.crayon-syntax /*,
+.crayon-syntax **/
+{
+    font-family: Monaco, 'MonacoRegular', 'Courier New', monospace;
+    font-weight: 500;
+}
+
+.crayon-syntax .crayon-toolbar *::selection,
+.crayon-syntax .crayon-nums *::selection {
+    background: transparent;
+}
+
+/*
+
+This has been disabled to allow more flexibility in changing font sizes.
+
+.crayon-syntax,
+.crayon-syntax .crayon-nums,
+.crayon-syntax .crayon-plain,
+.crayon-syntax .crayon-pre {
+	font-size: 12px !important;
+	line-height: 15px !important;
+}
+*/
+
+.crayon-table .crayon-nums-content {
+    white-space: nowrap; /* Prevent wrapping line numbers in some themes */
+}
+
+.crayon-syntax .crayon-num,
+.crayon-syntax .crayon-pre .crayon-line,
+.crayon-syntax .crayon-toolbar *,
+.crayon-syntax .crayon-pre * {
+    font-family: inherit;
+    font-size: inherit !important;
+    line-height: inherit !important;
+    font-weight: inherit !important;
+    height: inherit;
+}
+
+.crayon-syntax .crayon-toolbar .crayon-button .crayon-button-icon {
+    background-image: url('../images/toolbar/buttons.png');
+    height: 16px !important;
+    width: 100%;
+    position: absolute;
+    left: 0;
+    top: 50%;
+    margin-top: -8px;
+}
+
+.crayon-syntax .crayon-toolbar .crayon-tools {
+    position: absolute;
+    right: 0;
+}
+
+.crayon-syntax.crayon-expanded {
+    position: absolute !important;
+    margin: 0 !important;
+}
+
+.crayon-syntax.crayon-expanded .crayon-main {
+    overflow: hidden !important;
+}
+
+.crayon-placeholder {
+    width: 100% !important;
+}
+
+.crayon-toolbar-visible .crayon-toolbar {
+    position: relative !important;
+    margin-top: 0 !important;
+    display: block !important;
+}
+
+.crayon-syntax.crayon-expanded .crayon-toolbar .crayon-tools {
+    position: relative;
+    right: auto;
+    float: left !important;
+}
+
+.crayon-syntax .crayon-plain-wrap {
+    height: auto !important;
+    padding: 0 !important;
+    margin: 0 !important;
+}
+
+.crayon-syntax .crayon-plain {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    opacity: 0;
+    padding: 0 5px;
+    margin: 0px;
+    border: none;
+    box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    box-shadow: none;
+    border-radius: 0px;
+    -webkit-box-shadow: none;
+    -moz-box-shadow: none;
+    /*white-space: pre-wrap;*/
+    white-space: pre;
+    word-wrap: normal;
+    overflow: auto;
+    resize: none;
+    color: #000;
+    background: #FFF;
+}
+
+.crayon-wrapped .crayon-plain {
+    white-space: pre-wrap;
+}
+
+.bbp-body .crayon-syntax {
+    clear: none !important;
+}
+
+/* End Code ======================== */
+
+/* Minimize ================= */
+.crayon-minimized .crayon-toolbar {
+    cursor: pointer;
+}
+
+.crayon-minimized .crayon-plain-wrap,
+.crayon-minimized .crayon-main,
+.crayon-minimized .crayon-toolbar .crayon-tools * {
+    display: none !important;
+}
+
+.crayon-minimized .crayon-toolbar .crayon-tools .crayon-minimize {
+    display: block !important;
+}
+
+.crayon-minimized .crayon-toolbar {
+    position: relative !important;
+}
+
+.crayon-syntax.crayon-minimized .crayon-toolbar {
+    border-bottom: none !important;
+}
+
+/* End Minimize ============= */
diff --git a/css/src/global_style.css b/css/src/global_style.css
new file mode 100644
index 0000000..82b6061
--- /dev/null
+++ b/css/src/global_style.css
@@ -0,0 +1,302 @@
+/* TinyMCE */
+.crayon-te *, #crayon-te-bar-content {
+    font-family: "Lucida Grande", Arial, sans-serif !important;
+    font-size: 12px;
+}
+
+.crayon-te input[type="text"], .crayon-te textarea {
+    background: #F9F9F9;
+    border: 1px solid #CCC;
+    box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.1);
+    -moz-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.1);
+    -webkit-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.1);
+    padding: 2px 4px;
+    -webkit-border-radius: 3px;
+    border-radius: 3px;
+    border-width: 1px;
+    border-style: solid;
+}
+
+.crayon-te #crayon-code {
+    font-family: monospace !important;
+}
+
+#crayon-te-content, #crayon-te-table {
+    width: 100%;
+    height: auto !important;
+}
+
+#crayon-range, #crayon-mark {
+    width: 100px;
+}
+
+#crayon-te-table th, #crayon-te-table td {
+    vertical-align: top;
+    text-align: left;
+}
+
+.rtl #crayon-te-table th, .rtl #crayon-te-table td {
+    text-align: right;
+}
+
+#crayon-te-table .crayon-tr-center td, #crayon-te-table .crayon-tr-center th {
+    vertical-align: middle;
+}
+
+#crayon-te-table .crayon-nowrap {
+    white-space: nowrap;
+}
+
+#crayon-te-bar {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+}
+
+#crayon-te-bar-content {
+    border: 1px solid #666;
+    border-bottom: none;
+    height: 26px;
+    line-height: 25px;
+    padding: 0px 8px;
+    padding-right: 0;
+    background-color: #222;
+    color: #CFCFCF;
+}
+
+#crayon-te-bar-content a {
+    line-height: 25px;
+    padding: 5px 10px;
+    color: #DDD;
+    font-weight: bold;
+    text-decoration: none !important;
+}
+
+#crayon-te-bar-content a:hover {
+    color: #FFF;
+}
+
+.crayon-te-seperator {
+    color: #666;
+    margin: 0;
+    padding: 0;
+}
+
+#crayon-te-bar-block {
+    height: 34px;
+    width: 100%;
+}
+
+#crayon-te-title {
+    float: left;
+}
+
+#crayon-te-controls {
+    float: right;
+}
+
+#crayon-url-th {
+    vertical-align: top !important;
+    padding-top: 5px;
+}
+
+.crayon-te-heading {
+    font-size: 14px;
+    font-weight: bold;
+}
+
+#crayon-te-settings-info {
+    text-align: center;
+}
+
+.crayon-te-section {
+    font-weight: bold;
+    padding: 0 10px;
+}
+
+#crayon-te-sub-section {
+    margin-left: 10px;
+}
+
+#crayon-te-sub-section .crayon-te-section {
+    font-weight: normal;
+    padding: 0;
+}
+
+#crayon-code {
+    height: 200px;
+    white-space: pre;
+    /*white-space: nowrap;
+    overflow: auto;*/
+}
+
+#crayon-code, #crayon-url {
+    width: 555px !important;
+}
+
+.crayon-disabled {
+    background: #EEE !important;
+}
+
+.qt_crayon_highlight {
+    background-image: -ms-linear-gradient(bottom, #daf2ff, white) !important;
+    background-image: -moz-linear-gradient(bottom, #daf2ff, white) !important;
+    background-image: -o-linear-gradient(bottom, #daf2ff, white) !important;
+    background-image: -webkit-linear-gradient(bottom, #daf2ff, white) !important;
+    background-image: linear-gradient(bottom, #daf2ff, white) !important;
+}
+
+.qt_crayon_highlight:hover {
+    background: #ddebf2 !important;
+}
+
+.crayon-tag-editor-button-wrapper {
+    display: inline-block;
+}
+
+/* TinyMCE v4 */
+.mce_crayon_tinymce {
+    padding: 0 !important;
+    margin: 2px 3px !important;
+}
+.mce-i-crayon_tinymce,
+.mce_crayon_tinymce {
+    background: url(../images/crayon_tinymce.png) 0 0 !important;
+}
+
+/* TinyMCE v3 - deprecated */
+a.mce_crayon_tinymce {
+  background-position: 2px 0 !important;
+}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_crayon_tinymce,
+.wp_themeSkin .mceButtonActive span.mce_crayon_tinymce {
+  background-position: -20px 0;
+}
+.wp_themeSkin span.mce_crayon_tinymce {
+  background: none !important;
+}
+
+#crayon-te-table {
+    margin-top: 26px;
+    padding: 10px;
+    border-collapse: separate !important;
+    border-spacing: 2px !important;
+}
+
+#crayon-te-table th {
+    width: 100px;
+}
+
+#crayon-te-clear {
+    margin-left: 10px;
+    color: #666;
+    background-color: #f4f4f4;
+    border: 1px solid #CCC;
+    border-radius: 3px;
+    margin-left: 8px;
+}
+
+#crayon-title {
+    width: 360px;
+}
+
+#TB_window.crayon-te-ajax {
+    overflow: auto !important;
+}
+
+#TB_window.crayon-te-ajax, #TB_window.crayon-te-ajax #TB_ajaxContent, #TB_window.crayon-te-ajax #TB_title {
+    width: 680px !important;
+}
+
+#TB_window.crayon-te-ajax #TB_ajaxContent {
+    padding: 0 !important;
+    margin: 0 !important;
+    width: 100% !important;
+    height: auto !important;
+    margin-top: 28px !important;
+}
+
+#TB_window.crayon-te-ajax #TB_title {
+    position: fixed !important;
+}
+
+#TB_window.crayon-te-ajax #TB_title .crayon-te-submit {
+    margin-top: 3px !important;
+    float: right !important;
+}
+
+#TB_window.crayon-te-ajax a {
+    color: #2587e2;
+    text-decoration: none;
+}
+
+#TB_window.crayon-te-ajax a:hover {
+    color: #499ce9;
+}
+
+.crayon-te-quote {
+    background: #DDD;
+    padding: 0 2px;
+}
+
+#crayon-te-submit-wrapper {
+    display: none;
+}
+
+#crayon-te-clear {
+    display: none;
+    margin: 0;
+    margin-top: 10px;
+}
+
+.crayon-syntax-pre {
+    background: red;
+    white-space: pre;
+    overflow: auto;
+    display: block;
+    word-wrap: break-word;
+}
+
+.crayon-question {
+    padding: 1px 4px !important;
+    text-decoration: none !important;
+    color: #83b3cb !important;
+    border-radius: 10px !important;
+    height: 15px !important;
+    width: 15px !important;
+}
+
+.crayon-question:hover {
+    background: #83b3cb !important;
+    color: white !important;
+    height: 15px !important;
+    width: 15px !important;
+}
+
+.crayon-setting {
+
+}
+
+.crayon-setting-changed, .crayon-setting-selected {
+    background: #fffaad !important;
+}
+
+.crayon-question:hover {
+    color: white;
+    background: #a6d6ef;
+}
+
+#crayon-te-warning {
+    display: none;
+}
+
+.crayon-te-info {
+    padding: 5px !important;
+    margin: 2px 0 !important;
+}
+
+#crayon-te-submit {
+    margin-bottom: 5px;
+}
+
diff --git a/fonts/adobe-source-sans.css b/fonts/adobe-source-sans.css
new file mode 100644
index 0000000..955d247
--- /dev/null
+++ b/fonts/adobe-source-sans.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'AdobeSourceSansSemibold';
+    src: url('adobe-source-sans/SourceSansPro-Semibold.eot');
+    src: url('adobe-source-sans/SourceSansPro-Semibold.eot?#iefix') format('embedded-opentype'),
+         url('adobe-source-sans/SourceSansPro-Semibold.otf.woff') format('woff'),
+         url('adobe-source-sans/SourceSansPro-Semibold.ttf.woff') format('truetype'),
+         url('adobe-source-sans/SourceSansPro-Semibold.svg#AdobeSourceSansSemibold') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-adobe-source-sans * {
+    font-family: AdobeSourceSans, 'AdobeSourceSansSemibold', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/adobe-source-sans/SourceSansPro-Semibold.eot b/fonts/adobe-source-sans/SourceSansPro-Semibold.eot
new file mode 100644
index 0000000..cba2a52
Binary files /dev/null and b/fonts/adobe-source-sans/SourceSansPro-Semibold.eot differ
diff --git a/fonts/adobe-source-sans/SourceSansPro-Semibold.otf.woff b/fonts/adobe-source-sans/SourceSansPro-Semibold.otf.woff
new file mode 100644
index 0000000..8a165ec
Binary files /dev/null and b/fonts/adobe-source-sans/SourceSansPro-Semibold.otf.woff differ
diff --git a/fonts/adobe-source-sans/SourceSansPro-Semibold.svg b/fonts/adobe-source-sans/SourceSansPro-Semibold.svg
new file mode 100644
index 0000000..8109329
--- /dev/null
+++ b/fonts/adobe-source-sans/SourceSansPro-Semibold.svg
@@ -0,0 +1,1117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fonts/adobe-source-sans/SourceSansPro-Semibold.ttf.woff b/fonts/adobe-source-sans/SourceSansPro-Semibold.ttf.woff
new file mode 100644
index 0000000..336956f
Binary files /dev/null and b/fonts/adobe-source-sans/SourceSansPro-Semibold.ttf.woff differ
diff --git a/fonts/arial.css b/fonts/arial.css
new file mode 100644
index 0000000..7292a1c
--- /dev/null
+++ b/fonts/arial.css
@@ -0,0 +1,3 @@
+.crayon-font-arial * {
+    font-family: Arial, sans-serif !important;
+}
\ No newline at end of file
diff --git a/fonts/consolas.css b/fonts/consolas.css
new file mode 100644
index 0000000..2926fac
--- /dev/null
+++ b/fonts/consolas.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'ConsolasRegular';
+    src: url('consolas/consolas-webfont.eot');
+    src: url('consolas/consolas-webfont.eot?#iefix') format('embedded-opentype'),
+         url('consolas/consolas-webfont.woff') format('woff'),
+         url('consolas/consolas-webfont.ttf') format('truetype'),
+         url('consolas/consolas-webfont.svg#ConsolasRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-consolas * {
+    font-family: Consolas, 'ConsolasRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/consolas/consolas-webfont.eot b/fonts/consolas/consolas-webfont.eot
new file mode 100644
index 0000000..9f1c219
Binary files /dev/null and b/fonts/consolas/consolas-webfont.eot differ
diff --git a/fonts/consolas/consolas-webfont.svg b/fonts/consolas/consolas-webfont.svg
new file mode 100644
index 0000000..a475e42
--- /dev/null
+++ b/fonts/consolas/consolas-webfont.svg
@@ -0,0 +1,261 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   :  2005 Microsoft Corporation All Rights Reserved
+Designer    : Lucas de Groot
+Foundry     : Microsoft Corporation
+Foundry URL : httpwwwmicrosoftcomtypographyctfonts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/consolas/consolas-webfont.ttf b/fonts/consolas/consolas-webfont.ttf
new file mode 100644
index 0000000..8a6914c
Binary files /dev/null and b/fonts/consolas/consolas-webfont.ttf differ
diff --git a/fonts/consolas/consolas-webfont.woff b/fonts/consolas/consolas-webfont.woff
new file mode 100644
index 0000000..2a1d6e0
Binary files /dev/null and b/fonts/consolas/consolas-webfont.woff differ
diff --git a/fonts/courier-new.css b/fonts/courier-new.css
new file mode 100644
index 0000000..074d4cd
--- /dev/null
+++ b/fonts/courier-new.css
@@ -0,0 +1,3 @@
+.crayon-font-courier-new * {
+    font-family: 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/droid-sans-mono.css b/fonts/droid-sans-mono.css
new file mode 100644
index 0000000..c05817c
--- /dev/null
+++ b/fonts/droid-sans-mono.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'DroidSansMonoRegular';
+    src: url('droid-sans-mono/droid-sans-mono-webfont.eot');
+    src: url('droid-sans-mono/droid-sans-mono-webfont.eot?#iefix') format('embedded-opentype'),
+         url('droid-sans-mono/droid-sans-mono-webfont.woff') format('woff'),
+         url('droid-sans-mono/droid-sans-mono-webfont.ttf') format('truetype'),
+         url('droid-sans-mono/droid-sans-mono-webfont.svg#DroidSansMonoRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-droid-sans-mono * {
+    font-family: Droid Sans Mono, 'DroidSansMonoRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/droid-sans-mono/droid-sans-mono-webfont.eot b/fonts/droid-sans-mono/droid-sans-mono-webfont.eot
new file mode 100644
index 0000000..47f5e15
Binary files /dev/null and b/fonts/droid-sans-mono/droid-sans-mono-webfont.eot differ
diff --git a/fonts/droid-sans-mono/droid-sans-mono-webfont.svg b/fonts/droid-sans-mono/droid-sans-mono-webfont.svg
new file mode 100644
index 0000000..d9fd959
--- /dev/null
+++ b/fonts/droid-sans-mono/droid-sans-mono-webfont.svg
@@ -0,0 +1,149 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Digitized data copyright  2006 Google Corporation
+Foundry     : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/droid-sans-mono/droid-sans-mono-webfont.ttf b/fonts/droid-sans-mono/droid-sans-mono-webfont.ttf
new file mode 100644
index 0000000..7996ca2
Binary files /dev/null and b/fonts/droid-sans-mono/droid-sans-mono-webfont.ttf differ
diff --git a/fonts/droid-sans-mono/droid-sans-mono-webfont.woff b/fonts/droid-sans-mono/droid-sans-mono-webfont.woff
new file mode 100644
index 0000000..235d3df
Binary files /dev/null and b/fonts/droid-sans-mono/droid-sans-mono-webfont.woff differ
diff --git a/fonts/inconsolata.css b/fonts/inconsolata.css
new file mode 100644
index 0000000..a750f0c
--- /dev/null
+++ b/fonts/inconsolata.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'InconsolataRegular';
+    src: url('inconsolata/inconsolata-webfont.eot');
+    src: url('inconsolata/inconsolata-webfont.eot?#iefix') format('embedded-opentype'),
+         url('inconsolata/inconsolata-webfont.woff') format('woff'),
+         url('inconsolata/inconsolata-webfont.ttf') format('truetype'),
+         url('inconsolata/inconsolata-webfont.svg#InconsolataRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-inconsolata * {
+    font-family: Inconsolata, 'InconsolataRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/inconsolata/inconsolata-webfont.eot b/fonts/inconsolata/inconsolata-webfont.eot
new file mode 100644
index 0000000..eabeb69
Binary files /dev/null and b/fonts/inconsolata/inconsolata-webfont.eot differ
diff --git a/fonts/inconsolata/inconsolata-webfont.svg b/fonts/inconsolata/inconsolata-webfont.svg
new file mode 100644
index 0000000..f079d08
--- /dev/null
+++ b/fonts/inconsolata/inconsolata-webfont.svg
@@ -0,0 +1,147 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Created by Raph Levien using his own tools and FontForge Copyright 2006 Raph Levien Released under the SIL Open Font License httpscriptssilorgOFL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/inconsolata/inconsolata-webfont.ttf b/fonts/inconsolata/inconsolata-webfont.ttf
new file mode 100644
index 0000000..9246862
Binary files /dev/null and b/fonts/inconsolata/inconsolata-webfont.ttf differ
diff --git a/fonts/inconsolata/inconsolata-webfont.woff b/fonts/inconsolata/inconsolata-webfont.woff
new file mode 100644
index 0000000..ad76430
Binary files /dev/null and b/fonts/inconsolata/inconsolata-webfont.woff differ
diff --git a/fonts/liberation-mono.css b/fonts/liberation-mono.css
new file mode 100644
index 0000000..8ae11a5
--- /dev/null
+++ b/fonts/liberation-mono.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'LiberationMonoRegular';
+    src: url('liberation-mono/liberation-mono-webfont.eot');
+    src: url('liberation-mono/liberation-mono-webfont.eot?#iefix') format('embedded-opentype'),
+         url('liberation-mono/liberation-mono-webfont.woff') format('woff'),
+         url('liberation-mono/liberation-mono-webfont.ttf') format('truetype'),
+         url('liberation-mono/liberation-mono-webfont.svg#LiberationMonoRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-liberation-mono * {
+    font-family: Liberation Mono, 'LiberationMonoRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/liberation-mono/liberation-mono-webfont.eot b/fonts/liberation-mono/liberation-mono-webfont.eot
new file mode 100644
index 0000000..3c18afb
Binary files /dev/null and b/fonts/liberation-mono/liberation-mono-webfont.eot differ
diff --git a/fonts/liberation-mono/liberation-mono-webfont.svg b/fonts/liberation-mono/liberation-mono-webfont.svg
new file mode 100644
index 0000000..6e020ac
--- /dev/null
+++ b/fonts/liberation-mono/liberation-mono-webfont.svg
@@ -0,0 +1,153 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Digitized data  2007 Ascender Corporation All rights reserved
+Designer    : Steve Matteson
+Foundry     : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/liberation-mono/liberation-mono-webfont.ttf b/fonts/liberation-mono/liberation-mono-webfont.ttf
new file mode 100644
index 0000000..c468528
Binary files /dev/null and b/fonts/liberation-mono/liberation-mono-webfont.ttf differ
diff --git a/fonts/liberation-mono/liberation-mono-webfont.woff b/fonts/liberation-mono/liberation-mono-webfont.woff
new file mode 100644
index 0000000..e4e6db8
Binary files /dev/null and b/fonts/liberation-mono/liberation-mono-webfont.woff differ
diff --git a/fonts/monaco.css b/fonts/monaco.css
new file mode 100644
index 0000000..5f88241
--- /dev/null
+++ b/fonts/monaco.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'MonacoRegular';
+    src: url('monaco/monaco-webfont.eot');
+    src: url('monaco/monaco-webfont.eot?#iefix') format('embedded-opentype'),
+         url('monaco/monaco-webfont.woff') format('woff'),
+         url('monaco/monaco-webfont.ttf') format('truetype'),
+         url('monaco/monaco-webfont.svg#MonacoRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-monaco * {
+    font-family: Monaco, 'MonacoRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/monaco/monaco-webfont.eot b/fonts/monaco/monaco-webfont.eot
new file mode 100644
index 0000000..cb24120
Binary files /dev/null and b/fonts/monaco/monaco-webfont.eot differ
diff --git a/fonts/monaco/monaco-webfont.svg b/fonts/monaco/monaco-webfont.svg
new file mode 100644
index 0000000..7478d44
--- /dev/null
+++ b/fonts/monaco/monaco-webfont.svg
@@ -0,0 +1,239 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   :  199091 Apple Computer Inc  199091 Type Solutions Inc  199091 The Font Bureau Inc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/monaco/monaco-webfont.ttf b/fonts/monaco/monaco-webfont.ttf
new file mode 100644
index 0000000..376bdab
Binary files /dev/null and b/fonts/monaco/monaco-webfont.ttf differ
diff --git a/fonts/monaco/monaco-webfont.woff b/fonts/monaco/monaco-webfont.woff
new file mode 100644
index 0000000..1d386f7
Binary files /dev/null and b/fonts/monaco/monaco-webfont.woff differ
diff --git a/fonts/monospace.css b/fonts/monospace.css
new file mode 100644
index 0000000..68c389c
--- /dev/null
+++ b/fonts/monospace.css
@@ -0,0 +1,3 @@
+.crayon-font-monospace * {
+    font-family: monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/sourcecodepro.css b/fonts/sourcecodepro.css
new file mode 100644
index 0000000..444cb9a
--- /dev/null
+++ b/fonts/sourcecodepro.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'source_code_proregular';
+    src: url('sourcecodepro/sourcecodepro-regular-webfont.eot');
+    src: url('sourcecodepro/sourcecodepro-regular-webfont.eot?#iefix') format('embedded-opentype'),
+         url('sourcecodepro/sourcecodepro-regular-webfont.woff') format('woff'),
+         url('sourcecodepro/sourcecodepro-regular-webfont.ttf') format('truetype'),
+         url('sourcecodepro/sourcecodepro-regular-webfont.svg#MonacoRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-sourcecodepro * {
+    font-family: Source Code Pro, 'source_code_proregular', Arial, sans-serif !important;
+}
diff --git a/fonts/sourcecodepro/sourcecodepro-regular-webfont.eot b/fonts/sourcecodepro/sourcecodepro-regular-webfont.eot
new file mode 100644
index 0000000..040c2d9
Binary files /dev/null and b/fonts/sourcecodepro/sourcecodepro-regular-webfont.eot differ
diff --git a/fonts/sourcecodepro/sourcecodepro-regular-webfont.svg b/fonts/sourcecodepro/sourcecodepro-regular-webfont.svg
new file mode 100644
index 0000000..489e0b9
--- /dev/null
+++ b/fonts/sourcecodepro/sourcecodepro-regular-webfont.svg
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/sourcecodepro/sourcecodepro-regular-webfont.ttf b/fonts/sourcecodepro/sourcecodepro-regular-webfont.ttf
new file mode 100644
index 0000000..7f283cc
Binary files /dev/null and b/fonts/sourcecodepro/sourcecodepro-regular-webfont.ttf differ
diff --git a/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff b/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff
new file mode 100644
index 0000000..89489a4
Binary files /dev/null and b/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff differ
diff --git a/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff2 b/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff2
new file mode 100644
index 0000000..98023e8
Binary files /dev/null and b/fonts/sourcecodepro/sourcecodepro-regular-webfont.woff2 differ
diff --git a/fonts/tahoma.css b/fonts/tahoma.css
new file mode 100644
index 0000000..227f186
--- /dev/null
+++ b/fonts/tahoma.css
@@ -0,0 +1,3 @@
+.crayon-font-tahoma * {
+    font-family: Tahoma, Arial, sans !important;
+}
\ No newline at end of file
diff --git a/fonts/times.css b/fonts/times.css
new file mode 100644
index 0000000..702b659
--- /dev/null
+++ b/fonts/times.css
@@ -0,0 +1,3 @@
+.crayon-font-times * {
+    font-family: Times New Roman, serif !important;
+}
\ No newline at end of file
diff --git a/fonts/ubuntu-mono.css b/fonts/ubuntu-mono.css
new file mode 100644
index 0000000..903d431
--- /dev/null
+++ b/fonts/ubuntu-mono.css
@@ -0,0 +1,14 @@
+@font-face {
+    font-family: 'UbuntuMonoRegular';
+    src: url('ubuntu-mono/ubuntu-mono-webfont.eot');
+    src: url('ubuntu-mono/ubuntu-mono-webfont.eot?#iefix') format('embedded-opentype'),
+         url('ubuntu-mono/ubuntu-mono-webfont.woff') format('woff'),
+         url('ubuntu-mono/ubuntu-mono-webfont.ttf') format('truetype'),
+         url('ubuntu-mono/ubuntu-mono-webfont.svg#UbuntuMonoRegular') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+.crayon-font-ubuntu-mono * {
+    font-family: Ubuntu Mono, 'UbuntuMonoRegular', 'Courier New', monospace !important;
+}
\ No newline at end of file
diff --git a/fonts/ubuntu-mono/ubuntu-mono-webfont.eot b/fonts/ubuntu-mono/ubuntu-mono-webfont.eot
new file mode 100644
index 0000000..10d090d
Binary files /dev/null and b/fonts/ubuntu-mono/ubuntu-mono-webfont.eot differ
diff --git a/fonts/ubuntu-mono/ubuntu-mono-webfont.svg b/fonts/ubuntu-mono/ubuntu-mono-webfont.svg
new file mode 100644
index 0000000..b8081c3
--- /dev/null
+++ b/fonts/ubuntu-mono/ubuntu-mono-webfont.svg
@@ -0,0 +1,146 @@
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Copyright 2011 Canonical Ltd  Licensed under the Ubuntu Font Licence 10
+Designer    : Dalton Maag Ltd
+Foundry     : Dalton Maag Ltd
+Foundry URL : httpwwwdaltonmaagcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
\ No newline at end of file
diff --git a/fonts/ubuntu-mono/ubuntu-mono-webfont.ttf b/fonts/ubuntu-mono/ubuntu-mono-webfont.ttf
new file mode 100644
index 0000000..7552607
Binary files /dev/null and b/fonts/ubuntu-mono/ubuntu-mono-webfont.ttf differ
diff --git a/fonts/ubuntu-mono/ubuntu-mono-webfont.woff b/fonts/ubuntu-mono/ubuntu-mono-webfont.woff
new file mode 100644
index 0000000..4fd9437
Binary files /dev/null and b/fonts/ubuntu-mono/ubuntu-mono-webfont.woff differ
diff --git a/fonts/verdana.css b/fonts/verdana.css
new file mode 100644
index 0000000..cffa746
--- /dev/null
+++ b/fonts/verdana.css
@@ -0,0 +1,3 @@
+.crayon-font-verdana * {
+    font-family: Verdana, Arial, sans !important;
+}
\ No newline at end of file
diff --git a/global.php b/global.php
new file mode 100644
index 0000000..3a2ad0e
--- /dev/null
+++ b/global.php
@@ -0,0 +1,250 @@
+");
+define('CRAYON_NL', "\r\n");
+define('CRAYON_BL', CRAYON_BR . CRAYON_NL);
+define('CRAYON_DASH', "==============================================================================");
+define('CRAYON_LINE', "------------------------------------------------------------------------------");
+
+// Load utilities
+
+require_once (CRAYON_UTIL_PHP);
+require_once (CRAYON_TIMER_PHP);
+require_once (CRAYON_LOG_PHP);
+
+// Turn on the error & exception handlers
+//crayon_handler_on();
+
+// GLOBAL FUNCTIONS
+
+// Check for forwardslash/backslash in folder path to structure paths
+function crayon_s($url = '') {
+    $url = strval($url);
+    if (!empty($url) && !preg_match('#(\\\\|/)$#', $url)) {
+        return $url . '/';
+    } else if (empty($url)) {
+        return '/';
+    } else {
+        return $url;
+    }
+}
+
+// Returns path using forward slashes, slash added at the end
+function crayon_pf($url, $slash = TRUE) {
+    $url = trim(strval($url));
+    if ($slash) {
+        $url = crayon_s($url);
+    }
+    return str_replace('\\', '/', $url);
+}
+
+// Returns path using back slashes
+function crayon_pb($url) {
+    return str_replace('/', '\\', crayon_s(trim(strval($url))));
+}
+
+// Get/Set plugin information
+function crayon_set_info($info_array) {
+    global $CRAYON_VERSION, $CRAYON_DATE, $CRAYON_AUTHOR, $CRAYON_WEBSITE;
+    if (!is_array($info_array)) {
+        return;
+    }
+    crayon_set_info_key('Version', $info_array, $CRAYON_VERSION);
+    crayon_set_info_key('Date', $info_array, $CRAYON_DATE);
+    crayon_set_info_key('AuthorName', $info_array, $CRAYON_AUTHOR);
+    crayon_set_info_key('PluginURI', $info_array, $CRAYON_WEBSITE);
+}
+
+function crayon_set_info_key($key, $array, &$info) {
+    if (array_key_exists($key, $array)) {
+        $info = $array[$key];
+    } else {
+        return FALSE;
+    }
+}
+
+function crayon_vargs(&$var, $default) {
+    $var = isset($var) ? $var : $default;
+}
+
+// Checks if the input is a valid PHP file and matches the $valid filename
+function crayon_is_php_file($filepath, $valid) {
+    $path = pathinfo(crayon_pf($filepath));
+    return is_file($filepath) && $path['extension'] === 'php' && $path['filename'] === $valid;
+}
+
+// Stops the script if crayon_is_php_file() returns false or a remote path is given
+function crayon_die_if_not_php($filepath, $valid) {
+    if (!crayon_is_php_file($filepath, $valid) || crayon_is_path_url($filepath)) {
+        die("[ERROR] '$filepath' is not a valid PHP file for '$valid'");
+    }
+}
+
+function crayon_is_path_url($path) {
+    $parts = parse_url($path);
+    return isset($parts['scheme']) && strlen($parts['scheme']) > 1;
+}
+
+// LANGUAGE TRANSLATION FUNCTIONS
+
+function crayon_load_plugin_textdomain() {
+    if (function_exists('load_plugin_textdomain')) {
+        load_plugin_textdomain(CRAYON_DOMAIN, false, CRAYON_DIR . CRAYON_TRANS_DIR);
+    }
+}
+
+function crayon__($text) {
+    if (function_exists('__')) {
+        return __($text, CRAYON_DOMAIN);
+    } else {
+        return $text;
+    }
+}
+
+function crayon_e($text) {
+    if (function_exists('_e')) {
+        _e($text, CRAYON_DOMAIN);
+    } else {
+        echo $text;
+    }
+}
+
+function crayon_n($singular, $plural, $count) {
+    if (function_exists('_n')) {
+        return _n($singular, $plural, $count, CRAYON_DOMAIN);
+    } else {
+        return $count > 1 ? $plural : $singular;
+    }
+}
+
+function crayon_x($text, $context) {
+    if (function_exists('_x')) {
+        return _x($text, $context, CRAYON_DOMAIN);
+    } else {
+        return $text;
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/js/jquery-colorpicker/.gitignore b/js/jquery-colorpicker/.gitignore
new file mode 100644
index 0000000..90ec22b
--- /dev/null
+++ b/js/jquery-colorpicker/.gitignore
@@ -0,0 +1 @@
+.svn
diff --git a/js/jquery-colorpicker/README b/js/jquery-colorpicker/README
new file mode 100644
index 0000000..038e717
--- /dev/null
+++ b/js/jquery-colorpicker/README
@@ -0,0 +1,231 @@
+jQuery.colorpicker v0.9.3
+
+Copyright (c) 2011-2012 Martijn W. van der Lee
+Licensed under the MIT.
+
+Full-featured colorpicker for jQueryUI with full theming support.
+Most images from jPicker by Christopher T. Tillman.
+Sourcecode created from scratch by Martijn W. van der Lee.
+
+IE support; make sure you have a doctype defined, or the colorpicker will not
+display correctly.
+
+Options:
+	alpha:				false
+		Whether or not to show the inputs for alpha.
+
+	altAlpha:			true
+		Change the opacity of the altField element(s) according to the alpha
+		setting.
+
+	altField:			''
+		Change the background color of the elements specified in this element.
+
+	altOnChange:		true
+		If true, the altField element(s) are updated on every change, otherwise
+		only upon closing.
+
+	altProperties:		'background-color'
+		Comma-separated list of CSS properties to set color of in the altField.
+		The following properties are allowed, all others are ignored.
+			background-color
+			color
+			border-color
+			outline-color
+
+	autoOpen:			false
+		If true, the dialog opens automatically upon page load.
+
+	buttonColorize:		false
+		If a buttonimage is specified, change the background color of the
+		image when the color is changed.
+
+	buttonImage:		'images/ui-colorpicker.png'
+		Same as jQueryUI DatePicker.
+
+	buttonImageOnly:	false
+		Same as jQueryUI DatePicker.
+
+	buttonText:			null
+		Same as jQueryUI DatePicker. If null, use language default.
+
+	closeOnEscape:		true
+		Close the window when pressing the Escape key on the keyboard.
+
+	closeOnOutside:		true
+		Close the window when clicking outside the colorpicker display.
+
+	color:				'#00FF00'
+		Initial color. Formats recognized are:
+			#rrggbb
+			rrggbb (same as previous, but without the #)
+			rgb(rrr,ggg,bbb)
+			rgba(rrr,ggg,bbb,a.a)
+			rgb(rrr%,ggg%,bbb%)
+			rgba(rrr%,ggg%,bbb%,aaa%)
+			w3c-defined color name
+
+	colorFormat:		'HEX'
+		Specifies the format of the color string returned in callbacks.
+		You can either specify one of the predefined formats:
+			#HEX	#112233
+			#HEX3	#123 if possible, otherwise false.
+			HEX		112233
+			HEX3	123 if possible, otherwise false.
+			RGB		rgb(123,45,67) if opaque, otherwise false.
+			RGBA	rgba(123,45,67,0.123%)
+			RGB%	rgb(12%,34%,56%) if opaque, otherwise false.
+			RGBA%	rgba(12%,34%,56%,0.123%)
+			HSL		hsl(123,45,67) if opaque, otherwise false.
+			HSLA	hsla(123,45,67,0.123%)
+			HSL%	hsl(12%,34%,56%) if opaque, otherwise false.
+			HSLA%	hsla(12%,34%,56%,0.123%)
+			NAME	Closest color name
+			EXACT	Exact name if possible, otherwise false.
+		or specify your own format...
+		Each color channel is specified as a pair of two characters.
+		The first character determines the color channel:
+			a			Alpha
+			r, g, b		RGB color space; red, green and blue
+			h, s, v		HSV color space; hue, saturation and value
+			c, m, y, k	CMYK color space; cyan, magenta, yellow and black
+			L, A, B		LAB color space; Luminosity, *A and *B.
+		The second character specifies the data type:
+			x			Two-digit hexadecimal notation.
+			d			Decimal (0-255) notation.
+			f			Floating point (0-1) notation, not rounded.
+			p			Percentage (0-100) notation, not rounded.
+		If you prefix a valid pair with a backslash, it won't be replaced.
+		All patterns are case sensitive.
+		For example, to create the common hex color format, use "#rxgxbx".
+		For an rgba() format, use "rgba(rd,gd,bd,af)"
+
+		You can also specify an array of formats where the first non-FALSE one
+		is returned. Note that the only formats able to return FALSE are the
+		predefined formats HEX3 and EXACT. For example, this array will output
+		HEX3 format if possible or HEX format otherwise:
+			['HEX3', 'HEX']
+
+	dragggable:			true
+		Make the dialog draggable if the header is visible and the dialog is
+		not inline.
+
+	duration:			'fast'
+		Same as jQueryUI DatePicker.
+
+	hsv:				true
+		Whether or not to show the inputs for HSV.
+
+	layout:				{ ... }
+		Set the position of elements in a table layout.
+		You could create any layout possible with HTML tables by specifying
+		cell position and size of each part.
+		@todo document how this works.
+
+	limit:				''
+		Limit the selectable colors to any of the predefined limits:
+				''			No limitations, allow 8bpp color for a palette of
+							all 16 million colors.
+				'websafe'	Set of 216 colors composed of 00, 33, 66, 99, cc
+							and ff color channel values in #rrggbb.
+				'nibble'	4 bits per color, can be easily converted to #rgb
+							format.
+							The palette is limited to 4096 colors.
+				'binary'	Allow only #00 or #ff as color channel values for
+							primary	colors only; only 8 colors are available
+							with this limit.
+				'name'		Limit to closest color name.
+
+	modal:
+		Ensures no other controls on screen can be used while the dialog is
+		opened.
+		Also look at showCancelButton and closeOnEscape to use in combination
+		with the modal option. closeOnOutside is redundant when used with modal.
+
+	mode:				'h'
+		Determines the functionality of the map and bar components. Allowed
+		values are; 'h', 's', 'l', 'r', 'g', 'b' or 'a', for hue, saturation,
+		luminosity, red, green, blue and alpha respectively.
+
+	parts:				''
+		Determine which parts to display.
+		Use any of the preset names ('full', 'popup' or 'inline') or specify
+		an array of part names (i.e. ['header', 'map', 'bar', 'hex', 'hsv',
+		'rgb', 'alpha', 'lab', 'cmyk', 'preview', 'swatches', 'footer']).
+		If an empty string is given, the parts will be automatically chosen as
+		preset 'popup' or 'inline' depending on the context in which the
+		colorpicker is used.
+
+	rgb:				true,		// Show RGB controls and modes
+		Whether or not to show the inputs for RGB.
+
+	regional:			'',
+		Sets the language to use. Note that you must load the appropriate
+		language file from the i18n directory. '' is included by default.
+
+	showAnim:			'fadeIn'
+		Same as jQueryUI DatePicker.
+
+	showCancelButton:	true
+		Show the Cancel button if buttonpane is visible.
+
+	showCloseButton:	true
+		Show the Close button if the header is visible.
+		If the dialog is inline, the close button is never shown.
+
+	showNoneButton:		false
+		Show the None/Revert button if buttonpane is visible.
+
+	showOn:				'focus'
+		Same as jQueryUI DatePicker.
+
+	showOptions:		{}
+		Same as jQueryUI DatePicker.
+
+	swatches:			null
+		'null' to show swatches of HTML colors or provide your own object
+		with colornames and {r:1, g:1, b:1} array.
+		For example { 'red': {r:1, g:0, b:0}, 'blue': {r:0, g:0, b:1} }
+
+	title:				null
+		Title to display in the header. If null, use language default.
+
+Events:
+	init:			null
+		Triggered on initially setting the color. Called only once.
+		Callbacks recieve same data as select event.
+
+	close:			null
+		Triggered when the popup is closed.
+		Callbacks recieve same data as select event and an additional number
+		of fields containing the current color in all supported color spaces.
+		These are rgb{}, hsv{}, cmyk{}, lab{}, hsl{} and a.
+		Most values are floating point numbers in range [0,1] for accuracy.
+		The a and b values in the lab color space have range [-1,1].
+
+	select:			null
+		Triggered on each change, confirmation (click on OK button) and
+		cancellation (click on Cancel, outside window or window close button)
+		respectively.
+
+		The event recieves a jQuery event object and a data object containing
+		the elements 'formatted' (with the color formatted according to
+		formatColor).
+
+		Note that select may be triggered in rapid succession when dragging
+		the mouse accross the map or bar and may be triggered without a change
+		in color upon specific user interactions.
+
+Methods:
+	open
+		Open the dialog
+
+	close
+		Close the dialog
+
+	destroy
+		Destroy the widget
+
+	setColor
+		Set the current color to the specified color. Accepts any
+		CSS-confirmant color specification.
\ No newline at end of file
diff --git a/js/jquery-colorpicker/TODO b/js/jquery-colorpicker/TODO
new file mode 100644
index 0000000..6916720
--- /dev/null
+++ b/js/jquery-colorpicker/TODO
@@ -0,0 +1,20 @@
+Fix the weird one-pixel vertical shift bug.
+	Caused by ui-widget class.
+	Only happens in Chrome and only on some, not all.
+	Disappears and re-appears at different zoom levels.
+In hex input, accept (and strip) '#' symbol on copy/past.
+Completely destroy object when closed.
+Enabled/disabled
+isRTL? What to RTL, besides button?
+Disable selection in MSIE: this.dialog.on('selectstart', function(event) { return false; })
+Special rendering mode for color_none? Use [X] images?
+Fix parsing from input with websafe colors
+Recognize "transparent" color name.
+Limit number of events triggered.
+Small size variant (128x128)
+isRTL? What to RTL, besides button?
+Undo/redo memory?
+ARIA support.
+Allow only set (dec/hex) characters in inputs
+Most-recently-used swatches
+HSL/HSV distance calculations should take into account cyclic hue.
\ No newline at end of file
diff --git a/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-en.js b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-en.js
new file mode 100644
index 0000000..82ff967
--- /dev/null
+++ b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-en.js
@@ -0,0 +1,27 @@
+jQuery(function($) {
+	$.colorpicker.regional['en'] = {
+		ok:				'OK',
+		cancel:			'Cancel',
+		none:			'None',
+		button:			'Color',
+		title:			'Pick a color',
+		transparent:	'Transparent',
+		hsvH:			'H',
+		hsvS:			'S',
+		hsvV:			'V',
+		rgbR:			'R',
+		rgbG:			'G',
+		rgbB:			'B',
+		labL:			'L',
+		labA:			'a',
+		labB:			'b',
+		hslH:			'H',
+		hslS:			'S',
+		hslL:			'L',
+		cmykC:			'C',
+		cmykM:			'M',
+		cmykY:			'Y',
+		cmykK:			'K',
+		alphaA:			'A'
+	};
+});
\ No newline at end of file
diff --git a/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-fr.js b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-fr.js
new file mode 100644
index 0000000..e981edf
--- /dev/null
+++ b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-fr.js
@@ -0,0 +1,27 @@
+jQuery(function($) {
+	$.colorpicker.regional['fr'] = {
+		ok:				'OK',
+		cancel:			'Annuler',
+		none:			'Aucune couleur',
+		button:			'Couleur',
+		title:			'Choisir une couleur',
+		transparent:	'Transparent',
+		hsvH:			'T',
+		hsvS:			'S',
+		hsvV:			'V',
+		rgbR:			'R',
+		rgbG:			'V',
+		rgbB:			'B',
+		labL:			'L',
+		labA:			'a',
+		labB:			'b',
+		hslH:			'T',
+		hslS:			'S',
+		hslL:			'L',
+		cmykC:			'C',
+		cmykM:			'M',
+		cmykY:			'J',
+		cmykK:			'N',
+		alphaA:			'A'
+	};
+});
diff --git a/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-nl.js b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-nl.js
new file mode 100644
index 0000000..48fa7eb
--- /dev/null
+++ b/js/jquery-colorpicker/i18n/jquery.ui.colorpicker-nl.js
@@ -0,0 +1,27 @@
+jQuery(function($) {
+	$.colorpicker.regional['nl'] = {
+		ok:				'OK',
+		cancel:			'Annuleren',
+		none:			'Geen',
+		button:			'Kleur',
+		title:			'Kies een kleur',
+		transparent:	'Transparant',
+		hsvH:			'H',
+		hsvS:			'S',
+		hsvV:			'V',
+		rgbR:			'R',
+		rgbG:			'G',
+		rgbB:			'B',
+		labL:			'L',
+		labA:			'a',
+		labB:			'b',
+		hslH:			'H',
+		hslS:			'S',
+		hslL:			'L',
+		cmykC:			'C',
+		cmykM:			'M',
+		cmykY:			'Y',
+		cmykK:			'K',
+		alphaA:			'A'
+	};
+});
\ No newline at end of file
diff --git a/js/jquery-colorpicker/images/bar-alpha.png b/js/jquery-colorpicker/images/bar-alpha.png
new file mode 100644
index 0000000..2950dae
Binary files /dev/null and b/js/jquery-colorpicker/images/bar-alpha.png differ
diff --git a/js/jquery-colorpicker/images/bar-opacity.png b/js/jquery-colorpicker/images/bar-opacity.png
new file mode 100644
index 0000000..e42ad08
Binary files /dev/null and b/js/jquery-colorpicker/images/bar-opacity.png differ
diff --git a/js/jquery-colorpicker/images/bar-pointer.png b/js/jquery-colorpicker/images/bar-pointer.png
new file mode 100644
index 0000000..6e980cf
Binary files /dev/null and b/js/jquery-colorpicker/images/bar-pointer.png differ
diff --git a/js/jquery-colorpicker/images/bar.png b/js/jquery-colorpicker/images/bar.png
new file mode 100644
index 0000000..80eb2bb
Binary files /dev/null and b/js/jquery-colorpicker/images/bar.png differ
diff --git a/js/jquery-colorpicker/images/map-opacity.png b/js/jquery-colorpicker/images/map-opacity.png
new file mode 100644
index 0000000..6756cee
Binary files /dev/null and b/js/jquery-colorpicker/images/map-opacity.png differ
diff --git a/js/jquery-colorpicker/images/map-pointer.png b/js/jquery-colorpicker/images/map-pointer.png
new file mode 100644
index 0000000..6499296
Binary files /dev/null and b/js/jquery-colorpicker/images/map-pointer.png differ
diff --git a/js/jquery-colorpicker/images/map.png b/js/jquery-colorpicker/images/map.png
new file mode 100644
index 0000000..853d38c
Binary files /dev/null and b/js/jquery-colorpicker/images/map.png differ
diff --git a/js/jquery-colorpicker/images/preview-opacity.png b/js/jquery-colorpicker/images/preview-opacity.png
new file mode 100644
index 0000000..0dd9a2f
Binary files /dev/null and b/js/jquery-colorpicker/images/preview-opacity.png differ
diff --git a/js/jquery-colorpicker/images/ui-colorpicker.png b/js/jquery-colorpicker/images/ui-colorpicker.png
new file mode 100644
index 0000000..e244c68
Binary files /dev/null and b/js/jquery-colorpicker/images/ui-colorpicker.png differ
diff --git a/js/jquery-colorpicker/index.html b/js/jquery-colorpicker/index.html
new file mode 100644
index 0000000..db9fae7
--- /dev/null
+++ b/js/jquery-colorpicker/index.html
@@ -0,0 +1,210 @@
+
+
+    
+        jQuery Colorpicker
+		
+		
+		
+		
+        
+		
+		
+		
+    
+    
+		

jQuery ColorPicker

+ +
+ + Basic <input> example, without any options: + +
+ + Basic <div> example, without any options: + + +
+ + Fully-featured example: + + +
+ + Localized to Dutch (nl): + + +
+ + Limit to websafe colors: + + +
+ + Alternative field class: + +
Background-color on outside, text color here
+
+ + +
+ + Events: +
+ + +
+ + Output formatting HSLA: + + + +
+ + Output format list: + + + +
+ + Dialog with Colorpicker popup (demonstrates z-index): + +
+ Basic <input> example, without any options: +
+ Basic <div> example, without any options: +
+ + +
+ + Modal (and showCancelButton, closeOnEscape, showCloseButton): + + +
+ + Input formatting: + + + diff --git a/js/jquery-colorpicker/jquery.colorpicker.css b/js/jquery-colorpicker/jquery.colorpicker.css new file mode 100644 index 0000000..8487cdc --- /dev/null +++ b/js/jquery-colorpicker/jquery.colorpicker.css @@ -0,0 +1,199 @@ +.ui-colorpicker, +.ui-dialog.ui-colorpicker { + width: auto; + white-space: nowrap; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ui-colorpicker-inline { + position: static; +} + +.ui-colorpicker-buttonset { + float: left; + margin-left: .4em; +} + +.ui-colorpicker-buttonset .ui-button { + margin: .5em 0 .5em 0; + cursor: pointer; +} + +.ui-colorpicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} + +.ui-colorpicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} + +.ui-colorpicker-buttonpane button.ui-colorpicker-current { + float: left; +} + +.ui-colorpicker table { + font-size: 100%; /* Reset browser table font-size */ + margin: 0; +} + +.ui-colorpicker table td { + vertical-align: top; +} + +.ui-colorpicker-padding-left { + padding-left: 10px; +} +.ui-colorpicker-padding-top { + padding-top: 10px; +} + +.ui-colorpicker-border { + border: 1px inset; + display: inline-block; +} + +/* Bar & map */ +.ui-colorpicker-map > *, +.ui-colorpicker-bar > * { + position: absolute; + cursor: crosshair; +} + +.ui-colorpicker-map-pointer, +.ui-colorpicker-bar-pointer { + position: absolute; +} +/* Map */ +.ui-colorpicker-map, +.ui-colorpicker-map > * { + display: block; + width: 256px; + height: 256px; + overflow: hidden; +} + +.ui-colorpicker-map-layer-1, +.ui-colorpicker-map-layer-2 { + background: url(images/map.png) no-repeat; +} + +.ui-colorpicker-map-layer-alpha { + background: url(images/map-opacity.png); +} + +.ui-colorpicker-map-pointer { + display: inline-block; + width: 15px; + height: 15px; + background: url(images/map-pointer.png) no-repeat; +} + +/* Bar */ +.ui-colorpicker-bar, +.ui-colorpicker-bar > * { + display: block; + width: 20px; + height: 256px; + overflow: hidden; + background-repeat: repeat-x; +} + +.ui-colorpicker-bar-layer-1, +.ui-colorpicker-bar-layer-2, +.ui-colorpicker-bar-layer-3, +.ui-colorpicker-bar-layer-4 { + background: url(images/bar.png) repeat-x; +} + +.ui-colorpicker-bar-layer-alpha { + background: url(images/bar-opacity.png); +} + +.ui-colorpicker-bar-layer-alphabar { + background: url(images/bar-alpha.png); +} + +.ui-colorpicker-bar-pointer { + display: inline-block; + width: 20px; + height: 7px; + background: url(images/bar-pointer.png) no-repeat; +} + +/* Preview */ +.ui-colorpicker-preview { + text-align: center; +} + +.ui-colorpicker-preview-initial { + cursor: pointer; +} + +.ui-colorpicker-preview-initial, +.ui-colorpicker-preview-current { + width: 50px; + height: 20px; + display: inline-block; +} + +.ui-colorpicker-preview-initial-alpha, +.ui-colorpicker-preview-current-alpha { + width: 50px; + height: 20px; + display: inline-block; + background: url(images/preview-opacity.png) repeat; +} + +/* Inputs */ +.ui-colorpicker-rgb label, +.ui-colorpicker-hsv label, +.ui-colorpicker-hsl label, +.ui-colorpicker-lab label, +.ui-colorpicker-cmyk label, +.ui-colorpicker-alpha label { + width: 1.5em; + display: inline-block; +} + +.ui-colorpicker-number { + margin: .1em; + width: 4em; +} + +/* Hex */ +.ui-colorpicker-hex { + text-align: center; +} + +/* Swatches */ +.ui-colorpicker-swatches { + width: 84px; + height: 256px; + overflow: auto; + background-color: #f8f8f8; +} + +.ui-colorpicker-swatch { + cursor: pointer; + float: left; + width: 11px; + height: 11px; + border-right: 1px solid black; + border-bottom: 1px solid black; +} \ No newline at end of file diff --git a/js/jquery-colorpicker/jquery.colorpicker.js b/js/jquery-colorpicker/jquery.colorpicker.js new file mode 100644 index 0000000..e19db7b --- /dev/null +++ b/js/jquery-colorpicker/jquery.colorpicker.js @@ -0,0 +1,2552 @@ +/*jslint devel: true, bitwise: true, regexp: true, browser: true, confusion: true, unparam: true, eqeq: true, white: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */ +/*globals jQuery,Color */ + +/* + * ColorPicker + * + * Copyright (c) 2011-2012 Martijn W. van der Lee + * Licensed under the MIT. + * + * Full-featured colorpicker for jQueryUI with full theming support. + * Most images from jPicker by Christopher T. Tillman. + * Sourcecode created from scratch by Martijn W. van der Lee. + */ + +(function ($) { + "use strict"; + + $.colorpicker = new function() { + this.regional = []; + this.regional[''] = { + ok: 'OK', + cancel: 'Cancel', + none: 'None', + button: 'Color', + title: 'Pick a color', + transparent: 'Transparent', + hsvH: 'H', + hsvS: 'S', + hsvV: 'V', + rgbR: 'R', + rgbG: 'G', + rgbB: 'B', + labL: 'L', + labA: 'a', + labB: 'b', + hslH: 'H', + hslS: 'S', + hslL: 'L', + cmykC: 'C', + cmykM: 'M', + cmykY: 'Y', + cmykK: 'K', + alphaA: 'A' + }; + }; + + var _colorpicker_index = 0, + + _container_popup = '', + + _container_inline = '
', + + _parts_lists = { + 'full': ['header', 'map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'lab', 'cmyk', 'preview', 'swatches', 'footer'], + 'popup': ['map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview', 'footer'], + 'draggable': ['header', 'map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview', 'footer'], + 'inline': ['map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview'] + }, + + _intToHex = function (dec) { + var result = Math.round(dec).toString(16); + if (result.length === 1) { + result = ('0' + result); + } + return result.toLowerCase(); + }, + + _formats = { + '#HEX': function(color) { + return _formatColor('#rxgxbx', color); + } + , '#HEX3': function(color) { + var hex3 = _formats.HEX3(color); + return hex3 === false? false : '#'+hex3; + } + , 'HEX': function(color) { + return _formatColor('rxgxbx', color); + } + , 'HEX3': function(color) { + var rgb = color.getRGB(), + r = Math.round(rgb.r * 255), + g = Math.round(rgb.g * 255), + b = Math.round(rgb.b * 255); + + if (((r >>> 4) == (r &= 0xf)) + && ((g >>> 4) == (g &= 0xf)) + && ((b >>> 4) == (b &= 0xf))) { + return r.toString(16)+g.toString(16)+b.toString(16); + } + return false; + } + , 'RGB': function(color) { + return color.getAlpha() >= 1 + ? _formatColor('rgb(rd,gd,bd)', color) + : false; + } + , 'RGBA': function(color) { + return _formatColor('rgba(rd,gd,bd,af)', color); + } + , 'RGB%': function(color) { + return color.getAlpha() >= 1 + ? _formatColor('rgb(rp%,gp%,bp%)', color) + : false; + } + , 'RGBA%': function(color) { + return _formatColor('rgba(rp%,gp%,bp%,af)', color); + } + , 'HSL': function(color) { + return color.getAlpha() >= 1 + ? _formatColor('hsl(hd,sd,vd)', color) + : false; + } + , 'HSLA': function(color) { + return _formatColor('hsla(hd,sd,vd,af)', color); + } + , 'HSL%': function(color) { + return color.getAlpha() >= 1 + ? _formatColor('hsl(hp%,sp%,vp%)', color) + : false; + } + , 'HSLA%': function(color) { + return _formatColor('hsla(hp%,sp%,vp%,af)', color); + } + , 'NAME': function(color) { + return _closestName(color); + } + , 'EXACT': function(color) { //@todo experimental. Implement a good fallback list + return _exactName(color); + } + }, + + _formatColor = function (formats, color) { + var that = this, + text = null, + types = { 'x': function(v) {return _intToHex(v * 255);} + , 'd': function(v) {return Math.round(v * 255);} + , 'f': function(v) {return v;} + , 'p': function(v) {return v * 100;} + }, + channels = color.getChannels(); + + if (!$.isArray(formats)) { + formats = [formats]; + } + + $.each(formats, function(index, format) { + if (_formats[format]) { + text = _formats[format](color); + return (text === false); + } else { + text = format.replace(/\\?[argbhsvcmykLAB][xdfp]/g, function(m) { + if (m.match(/^\\/)) { + return m.slice(1); + } + return types[m.charAt(1)](channels[m.charAt(0)]); + }); + return false; + } + }); + + return text; + }, + + _colors = { + 'black': {r: 0, g: 0, b: 0}, + 'dimgray': {r: 0.4117647058823529, g: 0.4117647058823529, b: 0.4117647058823529}, + 'gray': {r: 0.5019607843137255, g: 0.5019607843137255, b: 0.5019607843137255}, + 'darkgray': {r: 0.6627450980392157, g: 0.6627450980392157, b: 0.6627450980392157}, + 'silver': {r: 0.7529411764705882, g: 0.7529411764705882, b: 0.7529411764705882}, + 'lightgrey': {r: 0.8274509803921568, g: 0.8274509803921568, b: 0.8274509803921568}, + 'gainsboro': {r: 0.8627450980392157, g: 0.8627450980392157, b: 0.8627450980392157}, + 'whitesmoke': {r: 0.9607843137254902, g: 0.9607843137254902, b: 0.9607843137254902}, + 'white': {r: 1, g: 1, b: 1}, + 'rosybrown': {r: 0.7372549019607844, g: 0.5607843137254902, b: 0.5607843137254902}, + 'indianred': {r: 0.803921568627451, g: 0.3607843137254902, b: 0.3607843137254902}, + 'brown': {r: 0.6470588235294118, g: 0.16470588235294117, b: 0.16470588235294117}, + 'firebrick': {r: 0.6980392156862745, g: 0.13333333333333333, b: 0.13333333333333333}, + 'lightcoral': {r: 0.9411764705882353, g: 0.5019607843137255, b: 0.5019607843137255}, + 'maroon': {r: 0.5019607843137255, g: 0, b: 0}, + 'darkred': {r: 0.5450980392156862, g: 0, b: 0}, + 'red': {r: 1, g: 0, b: 0}, + 'snow': {r: 1, g: 0.9803921568627451, b: 0.9803921568627451}, + 'salmon': {r: 0.9803921568627451, g: 0.5019607843137255, b: 0.4470588235294118}, + 'mistyrose': {r: 1, g: 0.8941176470588236, b: 0.8823529411764706}, + 'tomato': {r: 1, g: 0.38823529411764707, b: 0.2784313725490196}, + 'darksalmon': {r: 0.9137254901960784, g: 0.5882352941176471, b: 0.47843137254901963}, + 'orangered': {r: 1, g: 0.27058823529411763, b: 0}, + 'coral': {r: 1, g: 0.4980392156862745, b: 0.3137254901960784}, + 'lightsalmon': {r: 1, g: 0.6274509803921569, b: 0.47843137254901963}, + 'sienna': {r: 0.6274509803921569, g: 0.3215686274509804, b: 0.17647058823529413}, + 'seashell': {r: 1, g: 0.9607843137254902, b: 0.9333333333333333}, + 'chocolate': {r: 0.8235294117647058, g: 0.4117647058823529, b: 0.11764705882352941}, + 'saddlebrown': {r: 0.5450980392156862, g: 0.27058823529411763, b: 0.07450980392156863}, + 'sandybrown': {r: 0.9568627450980393, g: 0.6431372549019608, b: 0.3764705882352941}, + 'peachpuff': {r: 1, g: 0.8549019607843137, b: 0.7254901960784313}, + 'peru': {r: 0.803921568627451, g: 0.5215686274509804, b: 0.24705882352941178}, + 'linen': {r: 0.9803921568627451, g: 0.9411764705882353, b: 0.9019607843137255}, + 'darkorange': {r: 1, g: 0.5490196078431373, b: 0}, + 'bisque': {r: 1, g: 0.8941176470588236, b: 0.7686274509803922}, + 'burlywood': {r: 0.8705882352941177, g: 0.7215686274509804, b: 0.5294117647058824}, + 'tan': {r: 0.8235294117647058, g: 0.7058823529411765, b: 0.5490196078431373}, + 'antiquewhite': {r: 0.9803921568627451, g: 0.9215686274509803, b: 0.8431372549019608}, + 'navajowhite': {r: 1, g: 0.8705882352941177, b: 0.6784313725490196}, + 'blanchedalmond': {r: 1, g: 0.9215686274509803, b: 0.803921568627451}, + 'papayawhip': {r: 1, g: 0.9372549019607843, b: 0.8352941176470589}, + 'orange': {r: 1, g: 0.6470588235294118, b: 0}, + 'moccasin': {r: 1, g: 0.8941176470588236, b: 0.7098039215686275}, + 'wheat': {r: 0.9607843137254902, g: 0.8705882352941177, b: 0.7019607843137254}, + 'oldlace': {r: 0.9921568627450981, g: 0.9607843137254902, b: 0.9019607843137255}, + 'floralwhite': {r: 1, g: 0.9803921568627451, b: 0.9411764705882353}, + 'goldenrod': {r: 0.8549019607843137, g: 0.6470588235294118, b: 0.12549019607843137}, + 'darkgoldenrod': {r: 0.7215686274509804, g: 0.5254901960784314, b: 0.043137254901960784}, + 'cornsilk': {r: 1, g: 0.9725490196078431, b: 0.8627450980392157}, + 'gold': {r: 1, g: 0.8431372549019608, b: 0}, + 'palegoldenrod': {r: 0.9333333333333333, g: 0.9098039215686274, b: 0.6666666666666666}, + 'khaki': {r: 0.9411764705882353, g: 0.9019607843137255, b: 0.5490196078431373}, + 'lemonchiffon': {r: 1, g: 0.9803921568627451, b: 0.803921568627451}, + 'darkkhaki': {r: 0.7411764705882353, g: 0.7176470588235294, b: 0.4196078431372549}, + 'beige': {r: 0.9607843137254902, g: 0.9607843137254902, b: 0.8627450980392157}, + 'lightgoldenrodyellow': {r: 0.9803921568627451, g: 0.9803921568627451, b: 0.8235294117647058}, + 'olive': {r: 0.5019607843137255, g: 0.5019607843137255, b: 0}, + 'yellow': {r: 1, g: 1, b: 0}, + 'lightyellow': {r: 1, g: 1, b: 0.8784313725490196}, + 'ivory': {r: 1, g: 1, b: 0.9411764705882353}, + 'olivedrab': {r: 0.4196078431372549, g: 0.5568627450980392, b: 0.13725490196078433}, + 'yellowgreen': {r: 0.6039215686274509, g: 0.803921568627451, b: 0.19607843137254902}, + 'darkolivegreen': {r: 0.3333333333333333, g: 0.4196078431372549, b: 0.1843137254901961}, + 'greenyellow': {r: 0.6784313725490196, g: 1, b: 0.1843137254901961}, + 'lawngreen': {r: 0.48627450980392156, g: 0.9882352941176471, b: 0}, + 'chartreuse': {r: 0.4980392156862745, g: 1, b: 0}, + 'darkseagreen': {r: 0.5607843137254902, g: 0.7372549019607844, b: 0.5607843137254902}, + 'forestgreen': {r: 0.13333333333333333, g: 0.5450980392156862, b: 0.13333333333333333}, + 'limegreen': {r: 0.19607843137254902, g: 0.803921568627451, b: 0.19607843137254902}, + 'lightgreen': {r: 0.5647058823529412, g: 0.9333333333333333, b: 0.5647058823529412}, + 'palegreen': {r: 0.596078431372549, g: 0.984313725490196, b: 0.596078431372549}, + 'darkgreen': {r: 0, g: 0.39215686274509803, b: 0}, + 'green': {r: 0, g: 0.5019607843137255, b: 0}, + 'lime': {r: 0, g: 1, b: 0}, + 'honeydew': {r: 0.9411764705882353, g: 1, b: 0.9411764705882353}, + 'mediumseagreen': {r: 0.23529411764705882, g: 0.7019607843137254, b: 0.44313725490196076}, + 'seagreen': {r: 0.1803921568627451, g: 0.5450980392156862, b: 0.3411764705882353}, + 'springgreen': {r: 0, g: 1, b: 0.4980392156862745}, + 'mintcream': {r: 0.9607843137254902, g: 1, b: 0.9803921568627451}, + 'mediumspringgreen': {r: 0, g: 0.9803921568627451, b: 0.6039215686274509}, + 'mediumaquamarine': {r: 0.4, g: 0.803921568627451, b: 0.6666666666666666}, + 'aquamarine': {r: 0.4980392156862745, g: 1, b: 0.8313725490196079}, + 'turquoise': {r: 0.25098039215686274, g: 0.8784313725490196, b: 0.8156862745098039}, + 'lightseagreen': {r: 0.12549019607843137, g: 0.6980392156862745, b: 0.6666666666666666}, + 'mediumturquoise': {r: 0.2823529411764706, g: 0.8196078431372549, b: 0.8}, + 'darkslategray': {r: 0.1843137254901961, g: 0.30980392156862746, b: 0.30980392156862746}, + 'paleturquoise': {r: 0.6862745098039216, g: 0.9333333333333333, b: 0.9333333333333333}, + 'teal': {r: 0, g: 0.5019607843137255, b: 0.5019607843137255}, + 'darkcyan': {r: 0, g: 0.5450980392156862, b: 0.5450980392156862}, + 'darkturquoise': {r: 0, g: 0.807843137254902, b: 0.8196078431372549}, + 'aqua': {r: 0, g: 1, b: 1}, + 'cyan': {r: 0, g: 1, b: 1}, + 'lightcyan': {r: 0.8784313725490196, g: 1, b: 1}, + 'azure': {r: 0.9411764705882353, g: 1, b: 1}, + 'cadetblue': {r: 0.37254901960784315, g: 0.6196078431372549, b: 0.6274509803921569}, + 'powderblue': {r: 0.6901960784313725, g: 0.8784313725490196, b: 0.9019607843137255}, + 'lightblue': {r: 0.6784313725490196, g: 0.8470588235294118, b: 0.9019607843137255}, + 'deepskyblue': {r: 0, g: 0.7490196078431373, b: 1}, + 'skyblue': {r: 0.5294117647058824, g: 0.807843137254902, b: 0.9215686274509803}, + 'lightskyblue': {r: 0.5294117647058824, g: 0.807843137254902, b: 0.9803921568627451}, + 'steelblue': {r: 0.27450980392156865, g: 0.5098039215686274, b: 0.7058823529411765}, + 'aliceblue': {r: 0.9411764705882353, g: 0.9725490196078431, b: 1}, + 'dodgerblue': {r: 0.11764705882352941, g: 0.5647058823529412, b: 1}, + 'slategray': {r: 0.4392156862745098, g: 0.5019607843137255, b: 0.5647058823529412}, + 'lightslategray': {r: 0.4666666666666667, g: 0.5333333333333333, b: 0.6}, + 'lightsteelblue': {r: 0.6901960784313725, g: 0.7686274509803922, b: 0.8705882352941177}, + 'cornflowerblue': {r: 0.39215686274509803, g: 0.5843137254901961, b: 0.9294117647058824}, + 'royalblue': {r: 0.2549019607843137, g: 0.4117647058823529, b: 0.8823529411764706}, + 'midnightblue': {r: 0.09803921568627451, g: 0.09803921568627451, b: 0.4392156862745098}, + 'lavender': {r: 0.9019607843137255, g: 0.9019607843137255, b: 0.9803921568627451}, + 'navy': {r: 0, g: 0, b: 0.5019607843137255}, + 'darkblue': {r: 0, g: 0, b: 0.5450980392156862}, + 'mediumblue': {r: 0, g: 0, b: 0.803921568627451}, + 'blue': {r: 0, g: 0, b: 1}, + 'ghostwhite': {r: 0.9725490196078431, g: 0.9725490196078431, b: 1}, + 'darkslateblue': {r: 0.2823529411764706, g: 0.23921568627450981, b: 0.5450980392156862}, + 'slateblue': {r: 0.41568627450980394, g: 0.35294117647058826, b: 0.803921568627451}, + 'mediumslateblue': {r: 0.4823529411764706, g: 0.40784313725490196, b: 0.9333333333333333}, + 'mediumpurple': {r: 0.5764705882352941, g: 0.4392156862745098, b: 0.8588235294117647}, + 'blueviolet': {r: 0.5411764705882353, g: 0.16862745098039217, b: 0.8862745098039215}, + 'indigo': {r: 0.29411764705882354, g: 0, b: 0.5098039215686274}, + 'darkorchid': {r: 0.6, g: 0.19607843137254902, b: 0.8}, + 'darkviolet': {r: 0.5803921568627451, g: 0, b: 0.8274509803921568}, + 'mediumorchid': {r: 0.7294117647058823, g: 0.3333333333333333, b: 0.8274509803921568}, + 'thistle': {r: 0.8470588235294118, g: 0.7490196078431373, b: 0.8470588235294118}, + 'plum': {r: 0.8666666666666667, g: 0.6274509803921569, b: 0.8666666666666667}, + 'violet': {r: 0.9333333333333333, g: 0.5098039215686274, b: 0.9333333333333333}, + 'purple': {r: 0.5019607843137255, g: 0, b: 0.5019607843137255}, + 'darkmagenta': {r: 0.5450980392156862, g: 0, b: 0.5450980392156862}, + 'magenta': {r: 1, g: 0, b: 1}, + 'fuchsia': {r: 1, g: 0, b: 1}, + 'orchid': {r: 0.8549019607843137, g: 0.4392156862745098, b: 0.8392156862745098}, + 'mediumvioletred': {r: 0.7803921568627451, g: 0.08235294117647059, b: 0.5215686274509804}, + 'deeppink': {r: 1, g: 0.0784313725490196, b: 0.5764705882352941}, + 'hotpink': {r: 1, g: 0.4117647058823529, b: 0.7058823529411765}, + 'palevioletred': {r: 0.8588235294117647, g: 0.4392156862745098, b: 0.5764705882352941}, + 'lavenderblush': {r: 1, g: 0.9411764705882353, b: 0.9607843137254902}, + 'crimson': {r: 0.8627450980392157, g: 0.0784313725490196, b: 0.23529411764705882}, + 'pink': {r: 1, g: 0.7529411764705882, b: 0.796078431372549}, + 'lightpink': {r: 1, g: 0.7137254901960784, b: 0.7568627450980392} + }, + + _exactName = function(color) { + var name = false; + + $.each(_colors, function(n, color_b) { + if (color.equals(new Color(color_b.r, color_b.g, color_b.b))) { + name = n; + return false; + } + }); + + return name; + }, + + _closestName = function(color) { + var rgb = color.getRGB(), + distance = null, + name = false, + d; + + $.each(_colors, function(n, color_b) { + d = color.distance(new Color(color_b.r, color_b.g, color_b.b)); + if (d < distance || distance === null) { + name = n; + if (d == 0) { + return false; // can't get much closer than 0 + } + distance = d; + } + }); + + return name; + }, + + _parseHex = function(color) { + var c, + m; + + // {#}rrggbb + m = /^#?([a-fA-F0-9]{1,6})$/.exec(color); + if (m) { + c = parseInt(m[1], 16); + return new Color( + ((c >> 16) & 0xFF) / 255, + ((c >> 8) & 0xFF) / 255, + (c & 0xFF) / 255 + ); + } + + return false; + }, + + _parseColor = function(color) { + var name = $.trim(color).toLowerCase(), + m; + + if (color == '') { + return new Color(); + } + + if (_colors[name]) { + return new Color(_colors[name].r, _colors[name].g, _colors[name].b); + } + + // rgba(r,g,b,a) + m = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return new Color( + m[1] / 255, + m[2] / 255, + m[3] / 255, + parseFloat(m[4]) + ); + } + + // hsla(r,g,b,a) + m = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return (new Color()).setHSL( + m[1] / 255, + m[2] / 255, + m[3] / 255).setAlpha(parseFloat(m[4])); + } + + // rgba(r%,g%,b%,a%) + m = /^rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return new Color( + m[1] / 100, + m[2] / 100, + m[3] / 100, + m[4] / 100 + ); + } + + // hsla(r%,g%,b%,a%) + m = /^hsla?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return (new Color()).setHSL( + m[1] / 100, + m[2] / 100, + m[3] / 100).setAlpha(m[4] / 100); + } + + // #rrggbb + m = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color); + if (m) { + return new Color( + parseInt(m[1], 16) / 255, + parseInt(m[2], 16) / 255, + parseInt(m[3], 16) / 255 + ); + } + + // #rgb + m = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color); + if (m) { + return new Color( + parseInt(m[1] + m[1], 16) / 255, + parseInt(m[2] + m[2], 16) / 255, + parseInt(m[3] + m[3], 16) / 255 + ); + } + + return _parseHex(color); + }, + + _layoutTable = function(layout, callback) { + var bitmap, + x, + y, + width, height, + columns, rows, + index, + cell, + html, + w, + h, + colspan, + walked; + + layout.sort(function(a, b) { + if (a.pos[1] == b.pos[1]) { + return a.pos[0] - b.pos[0]; + } + return a.pos[1] - b.pos[1]; + }); + + // Determine dimensions of the table + width = 0; + height = 0; + $.each (layout, function(index, part) { + width = Math.max(width, part.pos[0] + part.pos[2]); + height = Math.max(height, part.pos[1] + part.pos[3]); + }); + + // Initialize bitmap + bitmap = []; + for (x = 0; x < width; ++x) { + bitmap.push([]); + } + + // Mark rows and columns which have layout assigned + rows = []; + columns = []; + $.each(layout, function(index, part) { + // mark columns + for (x = 0; x < part.pos[2]; x += 1) { + columns[part.pos[0] + x] = true; + } + for (y = 0; y < part.pos[3]; y += 1) { + rows[part.pos[1] + y] = true; + } + }); + + // Generate the table + html = ''; + cell = layout[index = 0]; + for (y = 0; y < height; ++y) { + html += ''; + for (x = 0; x < width; x) { + if (typeof cell !== 'undefined' && x == cell.pos[0] && y == cell.pos[1]) { + // Create a "real" cell + html += callback(cell, x, y); + + for (h = 0; h < cell.pos[3]; h +=1) { + for (w = 0; w < cell.pos[2]; w +=1) { + bitmap[x + w][y + h] = true; + } + } + + x += cell.pos[2]; + cell = layout[++index]; + } else { + // Fill in the gaps + colspan = 0; + walked = false; + + while (x < width && bitmap[x][y] === undefined && (cell === undefined || y < cell.pos[1] || (y == cell.pos[1] && x < cell.pos[0]))) { + if (columns[x] === true) { + colspan += 1; + } + walked = true; + x += 1; + } + + if (colspan > 0) { + html += ''; + } else if (!walked) { + x += 1; + } + } + } + html += ''; + } + + return '' + html + '
'; + }, + + _parts = { + header: function (inst) { + var that = this, + e = null, + _html =function() { + var title = inst.options.title || inst._getRegional('title'), + html = '' + title + ''; + + if (!inst.inline && inst.options.showCloseButton) { + html += '' + + 'close'; + } + + return '
' + html + '
'; + }; + + this.init = function() { + e = $(_html()).prependTo(inst.dialog); + + var close = $('.ui-dialog-titlebar-close', e); + inst._hoverable(close); + inst._focusable(close); + close.click(function(event) { + event.preventDefault(); + inst.close(); + }); + + if (!inst.inline && inst.options.draggable) { + inst.dialog.draggable({ + handle: e + }); + } + }; + }, + + map: function (inst) { + var that = this, + e = null, + mousemove_timeout = null, + _mousedown, _mouseup, _mousemove, _html; + + _mousedown = function (event) { + if (!inst.opened) { + return; + } + + var div = $('.ui-colorpicker-map-layer-pointer', e), + offset = div.offset(), + width = div.width(), + height = div.height(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + if (x >= 0 && x < width && y >= 0 && y < height) { + event.stopImmediatePropagation(); + event.preventDefault(); + e.unbind('mousedown', _mousedown); + $(document).bind('mouseup', _mouseup); + $(document).bind('mousemove', _mousemove); + _mousemove(event); + } + }; + + _mouseup = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(document).unbind('mouseup', _mouseup); + $(document).unbind('mousemove', _mousemove); + e.bind('mousedown', _mousedown); + }; + + _mousemove = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + + if (event.pageX === that.x && event.pageY === that.y) { + return; + } + that.x = event.pageX; + that.y = event.pageY; + + var div = $('.ui-colorpicker-map-layer-pointer', e), + offset = div.offset(), + width = div.width(), + height = div.height(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + x = Math.max(0, Math.min(x / width, 1)); + y = Math.max(0, Math.min(y / height, 1)); + + // interpret values + switch (inst.mode) { + case 'h': + inst.color.setHSV(null, x, 1 - y); + break; + + case 's': + case 'a': + inst.color.setHSV(x, null, 1 - y); + break; + + case 'v': + inst.color.setHSV(x, 1 - y, null); + break; + + case 'r': + inst.color.setRGB(null, 1 - y, x); + break; + + case 'g': + inst.color.setRGB(1 - y, null, x); + break; + + case 'b': + inst.color.setRGB(x, 1 - y, null); + break; + } + + inst._change(); + }; + + _html = function () { + var html = '
' + + ' ' + + ' ' + + (inst.options.alpha ? ' ' : '') + + '
'; + return html; + }; + + this.update = function () { + switch (inst.mode) { + case 'h': + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 0', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).hide(); + break; + + case 's': + case 'a': + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 -260px', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).css({'background-position': '0 -520px', 'opacity': ''}).show(); + break; + + case 'v': + $(e).css('background-color', 'black'); + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 -780px', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).hide(); + break; + + case 'r': + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 -1040px', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).css({'background-position': '0 -1300px', 'opacity': ''}).show(); + break; + + case 'g': + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 -1560px', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).css({'background-position': '0 -1820px', 'opacity': ''}).show(); + break; + + case 'b': + $('.ui-colorpicker-map-layer-1', e).css({'background-position': '0 -2080px', 'opacity': ''}).show(); + $('.ui-colorpicker-map-layer-2', e).css({'background-position': '0 -2340px', 'opacity': ''}).show(); + break; + } + that.repaint(); + }; + + this.repaint = function () { + var div = $('.ui-colorpicker-map-layer-pointer', e), + x = 0, + y = 0; + + switch (inst.mode) { + case 'h': + x = inst.color.getHSV().s * div.width(); + y = (1 - inst.color.getHSV().v) * div.width(); + $(e).css('background-color', inst.color.copy().normalize().toCSS()); + break; + + case 's': + case 'a': + x = inst.color.getHSV().h * div.width(); + y = (1 - inst.color.getHSV().v) * div.width(); + $('.ui-colorpicker-map-layer-2', e).css('opacity', 1 - inst.color.getHSV().s); + break; + + case 'v': + x = inst.color.getHSV().h * div.width(); + y = (1 - inst.color.getHSV().s) * div.width(); + $('.ui-colorpicker-map-layer-1', e).css('opacity', inst.color.getHSV().v); + break; + + case 'r': + x = inst.color.getRGB().b * div.width(); + y = (1 - inst.color.getRGB().g) * div.width(); + $('.ui-colorpicker-map-layer-2', e).css('opacity', inst.color.getRGB().r); + break; + + case 'g': + x = inst.color.getRGB().b * div.width(); + y = (1 - inst.color.getRGB().r) * div.width(); + $('.ui-colorpicker-map-layer-2', e).css('opacity', inst.color.getRGB().g); + break; + + case 'b': + x = inst.color.getRGB().r * div.width(); + y = (1 - inst.color.getRGB().g) * div.width(); + $('.ui-colorpicker-map-layer-2', e).css('opacity', inst.color.getRGB().b); + break; + } + + if (inst.options.alpha) { + $('.ui-colorpicker-map-layer-alpha', e).css('opacity', 1 - inst.color.getAlpha()); + } + + $('.ui-colorpicker-map-pointer', e).css({ + 'left': x - 7, + 'top': y - 7 + }); + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-map-container', inst.dialog)); + + e.bind('mousedown', _mousedown); + }; + }, + + bar: function (inst) { + var that = this, + e = null, + _mousedown, _mouseup, _mousemove, _html; + + _mousedown = function (event) { + if (!inst.opened) { + return; + } + + var div = $('.ui-colorpicker-bar-layer-pointer', e), + offset = div.offset(), + width = div.width(), + height = div.height(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + if (x >= 0 && x < width && y >= 0 && y < height) { + event.stopImmediatePropagation(); + event.preventDefault(); + e.unbind('mousedown', _mousedown); + $(document).bind('mouseup', _mouseup); + $(document).bind('mousemove', _mousemove); + _mousemove(event); + } + }; + + _mouseup = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(document).unbind('mouseup', _mouseup); + $(document).unbind('mousemove', _mousemove); + e.bind('mousedown', _mousedown); + }; + + _mousemove = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + + if (event.pageY === that.y) { + return; + } + that.y = event.pageY; + + var div = $('.ui-colorpicker-bar-layer-pointer', e), + offset = div.offset(), + height = div.height(), + y = event.pageY - offset.top; + + y = Math.max(0, Math.min(y / height, 1)); + + // interpret values + switch (inst.mode) { + case 'h': + inst.color.setHSV(1 - y, null, null); + break; + + case 's': + inst.color.setHSV(null, 1 - y, null); + break; + + case 'v': + inst.color.setHSV(null, null, 1 - y); + break; + + case 'r': + inst.color.setRGB(1 - y, null, null); + break; + + case 'g': + inst.color.setRGB(null, 1 - y, null); + break; + + case 'b': + inst.color.setRGB(null, null, 1 - y); + break; + + case 'a': + inst.color.setAlpha(1 - y); + break; + } + + inst._change(); + }; + + _html = function () { + var html = '
' + + ' ' + + ' ' + + ' ' + + ' '; + + if (inst.options.alpha) { + html += ' ' + + ' '; + } + + html += '
'; + + return html; + }; + + this.update = function () { + switch (inst.mode) { + case 'h': + case 's': + case 'v': + case 'r': + case 'g': + case 'b': + $('.ui-colorpicker-bar-layer-alpha', e).show(); + $('.ui-colorpicker-bar-layer-alphabar', e).hide(); + break; + + case 'a': + $('.ui-colorpicker-bar-layer-alpha', e).hide(); + $('.ui-colorpicker-bar-layer-alphabar', e).show(); + break; + } + + switch (inst.mode) { + case 'h': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 0', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).hide(); + $('.ui-colorpicker-bar-layer-3', e).hide(); + $('.ui-colorpicker-bar-layer-4', e).hide(); + break; + + case 's': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 -260px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).css({'background-position': '0 -520px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-3', e).hide(); + $('.ui-colorpicker-bar-layer-4', e).hide(); + break; + + case 'v': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 -520px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).hide(); + $('.ui-colorpicker-bar-layer-3', e).hide(); + $('.ui-colorpicker-bar-layer-4', e).hide(); + break; + + case 'r': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 -1560px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).css({'background-position': '0 -1300px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-3', e).css({'background-position': '0 -780px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-4', e).css({'background-position': '0 -1040px', 'opacity': ''}).show(); + break; + + case 'g': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 -2600px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).css({'background-position': '0 -2340px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-3', e).css({'background-position': '0 -1820px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-4', e).css({'background-position': '0 -2080px', 'opacity': ''}).show(); + break; + + case 'b': + $('.ui-colorpicker-bar-layer-1', e).css({'background-position': '0 -3640px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-2', e).css({'background-position': '0 -3380px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-3', e).css({'background-position': '0 -2860px', 'opacity': ''}).show(); + $('.ui-colorpicker-bar-layer-4', e).css({'background-position': '0 -3120px', 'opacity': ''}).show(); + break; + + case 'a': + $('.ui-colorpicker-bar-layer-1', e).hide(); + $('.ui-colorpicker-bar-layer-2', e).hide(); + $('.ui-colorpicker-bar-layer-3', e).hide(); + $('.ui-colorpicker-bar-layer-4', e).hide(); + break; + } + that.repaint(); + }; + + this.repaint = function () { + var div = $('.ui-colorpicker-bar-layer-pointer', e), + y = 0; + + switch (inst.mode) { + case 'h': + y = (1 - inst.color.getHSV().h) * div.height(); + break; + + case 's': + y = (1 - inst.color.getHSV().s) * div.height(); + $('.ui-colorpicker-bar-layer-2', e).css('opacity', 1 - inst.color.getHSV().v); + $(e).css('background-color', inst.color.copy().normalize().toCSS()); + break; + + case 'v': + y = (1 - inst.color.getHSV().v) * div.height(); + $(e).css('background-color', inst.color.copy().normalize().toCSS()); + break; + + case 'r': + y = (1 - inst.color.getRGB().r) * div.height(); + $('.ui-colorpicker-bar-layer-2', e).css('opacity', Math.max(0, (inst.color.getRGB().b - inst.color.getRGB().g))); + $('.ui-colorpicker-bar-layer-3', e).css('opacity', Math.max(0, (inst.color.getRGB().g - inst.color.getRGB().b))); + $('.ui-colorpicker-bar-layer-4', e).css('opacity', Math.min(inst.color.getRGB().b, inst.color.getRGB().g)); + break; + + case 'g': + y = (1 - inst.color.getRGB().g) * div.height(); + $('.ui-colorpicker-bar-layer-2', e).css('opacity', Math.max(0, (inst.color.getRGB().b - inst.color.getRGB().r))); + $('.ui-colorpicker-bar-layer-3', e).css('opacity', Math.max(0, (inst.color.getRGB().r - inst.color.getRGB().b))); + $('.ui-colorpicker-bar-layer-4', e).css('opacity', Math.min(inst.color.getRGB().r, inst.color.getRGB().b)); + break; + + case 'b': + y = (1 - inst.color.getRGB().b) * div.height(); + $('.ui-colorpicker-bar-layer-2', e).css('opacity', Math.max(0, (inst.color.getRGB().r - inst.color.getRGB().g))); + $('.ui-colorpicker-bar-layer-3', e).css('opacity', Math.max(0, (inst.color.getRGB().g - inst.color.getRGB().r))); + $('.ui-colorpicker-bar-layer-4', e).css('opacity', Math.min(inst.color.getRGB().r, inst.color.getRGB().g)); + break; + + case 'a': + y = (1 - inst.color.getAlpha()) * div.height(); + $(e).css('background-color', inst.color.copy().normalize().toCSS()); + break; + } + + if (inst.mode !== 'a') { + $('.ui-colorpicker-bar-layer-alpha', e).css('opacity', 1 - inst.color.getAlpha()); + } + + $('.ui-colorpicker-bar-pointer', e).css('top', y - 3); + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-bar-container', inst.dialog)); + + e.bind('mousedown', _mousedown); + }; + }, + + preview: function (inst) { + var that = this, + e = null, + _html; + + _html = function () { + return '
' + + '
' + + '
' + + '
'; + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-preview-container', inst.dialog)); + + $('.ui-colorpicker-preview-initial', e).click(function () { + inst.color = inst.currentColor.copy(); + inst._change(); + }); + + }; + + this.update = function () { + if (inst.options.alpha) { + $('.ui-colorpicker-preview-initial-alpha, .ui-colorpicker-preview-current-alpha', e).show(); + } else { + $('.ui-colorpicker-preview-initial-alpha, .ui-colorpicker-preview-current-alpha', e).hide(); + } + + this.repaint(); + }; + + this.repaint = function () { + $('.ui-colorpicker-preview-initial', e).css('background-color', inst.currentColor.toCSS()).attr('title', inst.currentColor.toHex()); + $('.ui-colorpicker-preview-initial-alpha', e).css('opacity', 1 - inst.currentColor.getAlpha()); + $('.ui-colorpicker-preview-current', e).css('background-color', inst.color.toCSS()).attr('title', inst.color.toHex()); + $('.ui-colorpicker-preview-current-alpha', e).css('opacity', 1 - inst.color.getAlpha()); + }; + }, + + hsv: function (inst) { + var that = this, + e = null, + _html; + + _html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
°
' + + '
%
' + + '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-hsv-container', inst.dialog)); + + $('.ui-colorpicker-mode', e).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + $('.ui-colorpicker-number', e).bind('change keyup', function () { + inst.color.setHSV( + $('.ui-colorpicker-hsv-h .ui-colorpicker-number', e).val() / 360, + $('.ui-colorpicker-hsv-s .ui-colorpicker-number', e).val() / 100, + $('.ui-colorpicker-hsv-v .ui-colorpicker-number', e).val() / 100 + ); + inst._change(); + }); + }; + + this.repaint = function () { + var hsv = inst.color.getHSV(); + hsv.h *= 360; + hsv.s *= 100; + hsv.v *= 100; + + $.each(hsv, function (index, value) { + var input = $('.ui-colorpicker-hsv-' + index + ' .ui-colorpicker-number', e); + value = Math.round(value); + if (input.val() !== value) { + input.val(value); + } + }); + }; + + this.update = function () { + $('.ui-colorpicker-mode', e).each(function () { + $(this).attr('checked', $(this).val() === inst.mode); + }); + this.repaint(); + }; + }, + + rgb: function (inst) { + var that = this, + e = null, + _html; + + _html = function () { + var html = ''; + + if (inst.options.rgb) { + html += '
' + + '
' + + '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-rgb-container', inst.dialog)); + + $('.ui-colorpicker-mode', e).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + $('.ui-colorpicker-number', e).bind('change keyup', function () { + inst.color.setRGB( + $('.ui-colorpicker-rgb-r .ui-colorpicker-number', e).val() / 255, + $('.ui-colorpicker-rgb-g .ui-colorpicker-number', e).val() / 255, + $('.ui-colorpicker-rgb-b .ui-colorpicker-number', e).val() / 255 + ); + + inst._change(); + }); + }; + + this.repaint = function () { + $.each(inst.color.getRGB(), function (index, value) { + var input = $('.ui-colorpicker-rgb-' + index + ' .ui-colorpicker-number', e); + value = Math.round(value * 255); + if (input.val() !== value) { + input.val(value); + } + }); + }; + + this.update = function () { + $('.ui-colorpicker-mode', e).each(function () { + $(this).attr('checked', $(this).val() === inst.mode); + }); + this.repaint(); + }; + }, + + lab: function (inst) { + var that = this, + part = null, + html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
' + + '
' + + '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + var data = 0; + + part = $(html()).appendTo($('.ui-colorpicker-lab-container', inst.dialog)); + + $('.ui-colorpicker-number', part).on('change keyup', function (event) { + inst.color.setLAB( + parseInt($('.ui-colorpicker-lab-l .ui-colorpicker-number', part).val(), 10) / 100, + (parseInt($('.ui-colorpicker-lab-a .ui-colorpicker-number', part).val(), 10) + 128) / 255, + (parseInt($('.ui-colorpicker-lab-b .ui-colorpicker-number', part).val(), 10) + 128) / 255 + ); + inst._change(); + }); + }; + + this.repaint = function () { + var lab = inst.color.getLAB(); + lab.l *= 100; + lab.a = (lab.a * 255) - 128; + lab.b = (lab.b * 255) - 128; + + $.each(lab, function (index, value) { + var input = $('.ui-colorpicker-lab-' + index + ' .ui-colorpicker-number', part); + value = Math.round(value); + if (input.val() !== value) { + input.val(value); + } + }); + }; + + this.update = function () { + this.repaint(); + }; + + }, + + cmyk: function (inst) { + var that = this, + part = null, + html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
%
' + + '
%
' + + '
%
' + + '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo($('.ui-colorpicker-cmyk-container', inst.dialog)); + + $('.ui-colorpicker-number', part).on('change keyup', function (event) { + inst.color.setCMYK( + parseInt($('.ui-colorpicker-cmyk-c .ui-colorpicker-number', part).val(), 10) / 100, + parseInt($('.ui-colorpicker-cmyk-m .ui-colorpicker-number', part).val(), 10) / 100, + parseInt($('.ui-colorpicker-cmyk-y .ui-colorpicker-number', part).val(), 10) / 100, + parseInt($('.ui-colorpicker-cmyk-k .ui-colorpicker-number', part).val(), 10) / 100 + ); + inst._change(); + }); + }; + + this.repaint = function () { + $.each(inst.color.getCMYK(), function (index, value) { + var input = $('.ui-colorpicker-cmyk-' + index + ' .ui-colorpicker-number', part); + value = Math.round(value * 100); + if (input.val() !== value) { + input.val(value); + } + }); + }; + + this.update = function () { + this.repaint(); + }; + + }, + + alpha: function (inst) { + var that = this, + e = null, + _html; + + _html = function () { + var html = ''; + + if (inst.options.alpha) { + html += '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-alpha-container', inst.dialog)); + + $('.ui-colorpicker-mode', e).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + $('.ui-colorpicker-number', e).bind('change keyup', function () { + inst.color.setAlpha($('.ui-colorpicker-a .ui-colorpicker-number', e).val() / 100); + inst._change(); + }); + }; + + this.update = function () { + $('.ui-colorpicker-mode', e).each(function () { + $(this).attr('checked', $(this).val() === inst.mode); + }); + this.repaint(); + }; + + this.repaint = function () { + var input = $('.ui-colorpicker-a .ui-colorpicker-number', e), + value = Math.round(inst.color.getAlpha() * 100); + if (!input.is(':focus') && input.val() !== value) { + input.val(value); + } + }; + }, + + hex: function (inst) { + var that = this, + e = null, + _html; + + _html = function () { + var html = ''; + + if (inst.options.alpha) { + html += ''; + } + + html += ''; + + return '
' + html + '
'; + }; + + this.init = function () { + e = $(_html()).appendTo($('.ui-colorpicker-hex-container', inst.dialog)); + + // repeat here makes the invalid input disappear faster + $('.ui-colorpicker-hex-input', e).bind('change keydown keyup', function (a, b, c) { + if (/[^a-fA-F0-9]/.test($(this).val())) { + $(this).val($(this).val().replace(/[^a-fA-F0-9]/, '')); + } + }); + + $('.ui-colorpicker-hex-input', e).bind('change keyup', function () { + // repeat here makes sure that the invalid input doesn't get parsed + inst.color = _parseHex($(this).val()).setAlpha(inst.color.getAlpha()); + inst._change(); + }); + + $('.ui-colorpicker-hex-alpha', e).bind('change keydown keyup', function () { + if (/[^a-fA-F0-9]/.test($(this).val())) { + $(this).val($(this).val().replace(/[^a-fA-F0-9]/, '')); + } + }); + + $('.ui-colorpicker-hex-alpha', e).bind('change keyup', function () { + inst.color.setAlpha(parseInt($('.ui-colorpicker-hex-alpha', e).val(), 16) / 255); + inst._change(); + }); + }; + + this.update = function () { + this.repaint(); + }; + + this.repaint = function () { + if (!$('.ui-colorpicker-hex-input', e).is(':focus')) { + $('.ui-colorpicker-hex-input', e).val(inst.color.toHex(true)); + } + + if (!$('.ui-colorpicker-hex-alpha', e).is(':focus')) { + $('.ui-colorpicker-hex-alpha', e).val(_intToHex(inst.color.getAlpha() * 255)); + } + }; + }, + + swatches: function (inst) { + var that = this, + part = null, + html = function () { + var html = ''; + + $.each(inst.options.swatches, function (name, color) { + var c = new Color(color.r, color.g, color.b), + css = c.toCSS(); + html += '
'; + }); + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo($('.ui-colorpicker-swatches-container', inst.dialog)); + + $('.ui-colorpicker-swatch', part).click(function () { + inst.color = _parseColor($(this).css('background-color')); + inst._change(); + }); + }; + }, + + footer: function (inst) { + var that = this, + part = null, + id_transparent = 'ui-colorpicker-special-transparent-'+_colorpicker_index, + id_none = 'ui-colorpicker-special-none-'+_colorpicker_index, + html = function () { + var html = ''; + + if (inst.options.alpha || (!inst.inline && inst.options.showNoneButton)) { + html += '
'; + + if (inst.options.alpha) { + html += ''; + } + if (!inst.inline && inst.options.showNoneButton) { + html += ''; + } + html += '
'; + } + + if (!inst.inline) { + html += '
'; + if (inst.options.showCancelButton) { + html += ''; + } + html += ''; + html += '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo(inst.dialog); + + $('.ui-colorpicker-ok', part).button().click(function () { + inst.close(); + }); + + $('.ui-colorpicker-cancel', part).button().click(function () { + inst.color = inst.currentColor.copy(); + inst._change(inst.color.set); + inst.close(); + }); + + //inst._getRegional('transparent') + $('.ui-colorpicker-buttonset', part).buttonset(); + + $('.ui-colorpicker-special-color', part).click(function () { + inst._change(); + }); + + $('#'+id_none, part).click(function () { + inst._change(false); + }); + + $('#'+id_transparent, part).click(function () { + inst.color.setAlpha(0); + inst._change(); + }); + }; + + this.repaint = function () { + if (!inst.color.set) { + $('.ui-colorpicker-special-none', part).attr('checked', true).button( "refresh" ); + } else if (inst.color.getAlpha() == 0) { + $('.ui-colorpicker-special-transparent', part).attr('checked', true).button( "refresh" ); + } else { + $('input', part).attr('checked', false).button( "refresh" ); + } + + $('.ui-colorpicker-cancel', part).button(inst.changed ? 'enable' : 'disable'); + }; + + this.update = function () {}; + } + }, + + Color = function () { + var spaces = { rgb: {r: 0, g: 0, b: 0}, + hsv: {h: 0, s: 0, v: 0}, + hsl: {h: 0, s: 0, l: 0}, + lab: {l: 0, a: 0, b: 0}, + cmyk: {c: 0, m: 0, y: 0, k: 1} + }, + a = 1, + arg, + args = arguments, + _clip = function(v) { + if (isNaN(v) || v === null) { + return 0; + } + if (typeof v == 'string') { + v = parseInt(v, 10); + } + return Math.max(0, Math.min(v, 1)); + }, + _hexify = function (number) { + var digits = '0123456789abcdef', + lsd = number % 16, + msd = (number - lsd) / 16, + hexified = digits.charAt(msd) + digits.charAt(lsd); + return hexified; + }, + _rgb_to_xyz = function(rgb) { + var r = (rgb.r > 0.04045) ? Math.pow((rgb.r + 0.055) / 1.055, 2.4) : rgb.r / 12.92, + g = (rgb.g > 0.04045) ? Math.pow((rgb.g + 0.055) / 1.055, 2.4) : rgb.g / 12.92, + b = (rgb.b > 0.04045) ? Math.pow((rgb.b + 0.055) / 1.055, 2.4) : rgb.b / 12.92; + + return { + x: r * 0.4124 + g * 0.3576 + b * 0.1805, + y: r * 0.2126 + g * 0.7152 + b * 0.0722, + z: r * 0.0193 + g * 0.1192 + b * 0.9505 + }; + }, + _xyz_to_rgb = function(xyz) { + var rgb = { + r: xyz.x * 3.2406 + xyz.y * -1.5372 + xyz.z * -0.4986, + g: xyz.x * -0.9689 + xyz.y * 1.8758 + xyz.z * 0.0415, + b: xyz.x * 0.0557 + xyz.y * -0.2040 + xyz.z * 1.0570 + }; + + rgb.r = (rgb.r > 0.0031308) ? 1.055 * Math.pow(rgb.r, (1 / 2.4)) - 0.055 : 12.92 * rgb.r; + rgb.g = (rgb.g > 0.0031308) ? 1.055 * Math.pow(rgb.g, (1 / 2.4)) - 0.055 : 12.92 * rgb.g; + rgb.b = (rgb.b > 0.0031308) ? 1.055 * Math.pow(rgb.b, (1 / 2.4)) - 0.055 : 12.92 * rgb.b; + + return rgb; + }, + _rgb_to_hsv = function(rgb) { + var minVal = Math.min(rgb.r, rgb.g, rgb.b), + maxVal = Math.max(rgb.r, rgb.g, rgb.b), + delta = maxVal - minVal, + del_R, del_G, del_B, + hsv = { + h: 0, + s: 0, + v: maxVal + }; + + if (delta === 0) { + hsv.h = 0; + hsv.s = 0; + } else { + hsv.s = delta / maxVal; + + del_R = (((maxVal - rgb.r) / 6) + (delta / 2)) / delta; + del_G = (((maxVal - rgb.g) / 6) + (delta / 2)) / delta; + del_B = (((maxVal - rgb.b) / 6) + (delta / 2)) / delta; + + if (rgb.r === maxVal) { + hsv.h = del_B - del_G; + } else if (rgb.g === maxVal) { + hsv.h = (1 / 3) + del_R - del_B; + } else if (rgb.b === maxVal) { + hsv.h = (2 / 3) + del_G - del_R; + } + + if (hsv.h < 0) { + hsv.h += 1; + } else if (hsv.h > 1) { + hsv.h -= 1; + } + } + + return hsv; + }, + _hsv_to_rgb = function(hsv) { + var rgb = { + r: 0, + g: 0, + b: 0 + }, + var_h, + var_i, + var_1, + var_2, + var_3; + + if (hsv.s === 0) { + rgb.r = rgb.g = rgb.b = hsv.v; + } else { + var_h = hsv.h === 1 ? 0 : hsv.h * 6; + var_i = Math.floor(var_h); + var_1 = hsv.v * (1 - hsv.s); + var_2 = hsv.v * (1 - hsv.s * (var_h - var_i)); + var_3 = hsv.v * (1 - hsv.s * (1 - (var_h - var_i))); + + if (var_i === 0) { + rgb.r = hsv.v; + rgb.g = var_3; + rgb.b = var_1; + } else if (var_i === 1) { + rgb.r = var_2; + rgb.g = hsv.v; + rgb.b = var_1; + } else if (var_i === 2) { + rgb.r = var_1; + rgb.g = hsv.v; + rgb.b = var_3; + } else if (var_i === 3) { + rgb.r = var_1; + rgb.g = var_2; + rgb.b = hsv.v; + } else if (var_i === 4) { + rgb.r = var_3; + rgb.g = var_1; + rgb.b = hsv.v; + } else { + rgb.r = hsv.v; + rgb.g = var_1; + rgb.b = var_2; + } + } + + return rgb; + }, + _rgb_to_hsl = function(rgb) { + var minVal = Math.min(rgb.r, rgb.g, rgb.b), + maxVal = Math.max(rgb.r, rgb.g, rgb.b), + delta = maxVal - minVal, + del_R, del_G, del_B, + hsl = { + h: 0, + s: 0, + l: (maxVal + minVal) / 2 + }; + + if (delta === 0) { + hsl.h = 0; + hsl.s = 0; + } else { + hsl.s = hsl.l < 0.5 ? delta / (maxVal + minVal) : delta / (2 - maxVal - minVal); + + del_R = (((maxVal - rgb.r) / 6) + (delta / 2)) / delta; + del_G = (((maxVal - rgb.g) / 6) + (delta / 2)) / delta; + del_B = (((maxVal - rgb.b) / 6) + (delta / 2)) / delta; + + if (rgb.r === maxVal) { + hsl.h = del_B - del_G; + } else if (rgb.g === maxVal) { + hsl.h = (1 / 3) + del_R - del_B; + } else if (rgb.b === maxVal) { + hsl.h = (2 / 3) + del_G - del_R; + } + + if (hsl.h < 0) { + hsl.h += 1; + } else if (hsl.h > 1) { + hsl.h -= 1; + } + } + + return hsl; + }, + _hsl_to_rgb = function(hsl) { + var var_1, + var_2, + hue_to_rgb = function(v1, v2, vH) { + if (vH < 0) { + vH += 1; + } + if (vH > 1) { + vH -= 1; + } + if ((6 * vH) < 1) { + return v1 + (v2 - v1) * 6 * vH; + } + if ((2 * vH) < 1) { + return v2; + } + if ((3 * vH) < 2) { + return v1 + (v2 - v1) * ((2 / 3) - vH) * 6; + } + return v1; + }; + + if (hsl.s === 0) { + return { + r: hsl.l, + g: hsl.l, + b: hsl.l + }; + } + + var_2 = (hsl.l < 0.5) ? hsl.l * (1 + hsl.s) : (hsl.l + hsl.s) - (hsl.s * hsl.l); + var_1 = 2 * hsl.l - var_2; + + return { + r: hue_to_rgb(var_1, var_2, hsl.h + (1 / 3)), + g: hue_to_rgb(var_1, var_2, hsl.h), + b: hue_to_rgb(var_1, var_2, hsl.h - (1 / 3)) + }; + }, + _xyz_to_lab = function(xyz) { + // CIE-L*ab D65 1931 + var x = xyz.x / 0.95047, + y = xyz.y, + z = xyz.z / 1.08883; + + x = (x > 0.008856) ? Math.pow(x, (1/3)) : (7.787 * x) + (16/116); + y = (y > 0.008856) ? Math.pow(y, (1/3)) : (7.787 * y) + (16/116); + z = (z > 0.008856) ? Math.pow(z, (1/3)) : (7.787 * z) + (16/116); + + return { + l: ((116 * y) - 16) / 100, // [0,100] + a: ((500 * (x - y)) + 128) / 255, // [-128,127] + b: ((200 * (y - z)) + 128) / 255 // [-128,127] + }; + }, + _lab_to_xyz = function(lab) { + var lab2 = { + l: lab.l * 100, + a: (lab.a * 255) - 128, + b: (lab.b * 255) - 128 + }, + xyz = { + x: 0, + y: (lab2.l + 16) / 116, + z: 0 + }; + + xyz.x = lab2.a / 500 + xyz.y; + xyz.z = xyz.y - lab2.b / 200; + + xyz.x = (Math.pow(xyz.x, 3) > 0.008856) ? Math.pow(xyz.x, 3) : (xyz.x - 16 / 116) / 7.787; + xyz.y = (Math.pow(xyz.y, 3) > 0.008856) ? Math.pow(xyz.y, 3) : (xyz.y - 16 / 116) / 7.787; + xyz.z = (Math.pow(xyz.z, 3) > 0.008856) ? Math.pow(xyz.z, 3) : (xyz.z - 16 / 116) / 7.787; + + xyz.x *= 0.95047; + xyz.y *= 1; + xyz.z *= 1.08883; + + return xyz; + }, + _rgb_to_cmy = function(rgb) { + return { + c: 1 - (rgb.r), + m: 1 - (rgb.g), + y: 1 - (rgb.b) + }; + }, + _cmy_to_rgb = function(cmy) { + return { + r: 1 - (cmy.c), + g: 1 - (cmy.m), + b: 1 - (cmy.y) + }; + }, + _cmy_to_cmyk = function(cmy) { + var K = 1; + + if (cmy.c < K) { + K = cmy.c; + } + if (cmy.m < K) { + K = cmy.m; + } + if (cmy.y < K) { + K = cmy.y; + } + + if (K == 1) { + return { + c: 0, + m: 0, + y: 0, + k: 1 + }; + } + + return { + c: (cmy.c - K) / (1 - K), + m: (cmy.m - K) / (1 - K), + y: (cmy.y - K) / (1 - K), + k: K + }; + }, + _cmyk_to_cmy = function(cmyk) { + return { + c: cmyk.c * (1 - cmyk.k) + cmyk.k, + m: cmyk.m * (1 - cmyk.k) + cmyk.k, + y: cmyk.y * (1 - cmyk.k) + cmyk.k + }; + }; + + this.set = true; + + this.setAlpha = function(_a) { + if (_a !== null) { + a = _clip(_a); + } + + return this; + }; + + this.getAlpha = function() { + return a; + }; + + this.setRGB = function(r, g, b) { + spaces = {rgb: this.getRGB()}; + if (r !== null) { + spaces.rgb.r = _clip(r); + } + if (g !== null) { + spaces.rgb.g = _clip(g); + } + if (b !== null) { + spaces.rgb.b = _clip(b); + } + + return this; + }; + + this.setHSV = function(h, s, v) { + spaces = {hsv: this.getHSV()}; + if (h !== null) { + spaces.hsv.h = _clip(h); + } + if (s !== null) { + spaces.hsv.s = _clip(s); + } + if (v !== null) { + spaces.hsv.v = _clip(v); + } + + return this; + }; + + this.setHSL = function(h, s, l) { + spaces = {hsl: this.getHSL()}; + if (h !== null) { + spaces.hsl.h = _clip(h); + } + if (s !== null) { + spaces.hsl.s = _clip(s); + } + if (l !== null) { + spaces.hsl.l = _clip(l); + } + + return this; + }; + + this.setLAB = function(l, a, b) { + spaces = {lab: this.getLAB()}; + if (l !== null) { + spaces.lab.l = _clip(l); + } + if (a !== null) { + spaces.lab.a = _clip(a); + } + if (b !== null) { + spaces.lab.b = _clip(b); + } + + return this; + }; + + this.setCMYK = function(c, m, y, k) { + spaces = {cmyk: this.getCMYK()}; + if (c !== null) { + spaces.cmyk.c = _clip(c); + } + if (m !== null) { + spaces.cmyk.m = _clip(m); + } + if (y !== null) { + spaces.cmyk.y = _clip(y); + } + if (k !== null) { + spaces.cmyk.k = _clip(k); + } + + return this; + }; + + this.getRGB = function() { + if (!spaces.rgb) { + spaces.rgb = spaces.lab ? _xyz_to_rgb(_lab_to_xyz(spaces.lab)) + : spaces.hsv ? _hsv_to_rgb(spaces.hsv) + : spaces.hsl ? _hsl_to_rgb(spaces.hsl) + : spaces.cmyk ? _cmy_to_rgb(_cmyk_to_cmy(spaces.cmyk)) + : {r: 0, g: 0, b: 0}; + spaces.rgb.r = _clip(spaces.rgb.r); + spaces.rgb.g = _clip(spaces.rgb.g); + spaces.rgb.b = _clip(spaces.rgb.b); + } + return $.extend({}, spaces.rgb); + }; + + this.getHSV = function() { + if (!spaces.hsv) { + spaces.hsv = spaces.lab ? _rgb_to_hsv(this.getRGB()) + : spaces.rgb ? _rgb_to_hsv(spaces.rgb) + : spaces.hsl ? _rgb_to_hsv(this.getRGB()) + : spaces.cmyk ? _rgb_to_hsv(this.getRGB()) + : {h: 0, s: 0, v: 0}; + spaces.hsv.h = _clip(spaces.hsv.h); + spaces.hsv.s = _clip(spaces.hsv.s); + spaces.hsv.v = _clip(spaces.hsv.v); + } + return $.extend({}, spaces.hsv); + }; + + this.getHSL = function() { + if (!spaces.hsl) { + spaces.hsl = spaces.rgb ? _rgb_to_hsl(spaces.rgb) + : spaces.hsv ? _rgb_to_hsl(this.getRGB()) + : spaces.cmyk ? _rgb_to_hsl(this.getRGB()) + : spaces.hsv ? _rgb_to_hsl(this.getRGB()) + : {h: 0, s: 0, l: 0}; + spaces.hsl.h = _clip(spaces.hsl.h); + spaces.hsl.s = _clip(spaces.hsl.s); + spaces.hsl.l = _clip(spaces.hsl.l); + } + return $.extend({}, spaces.hsl); + }; + + this.getCMYK = function() { + if (!spaces.cmyk) { + spaces.cmyk = spaces.rgb ? _cmy_to_cmyk(_rgb_to_cmy(spaces.rgb)) + : spaces.hsv ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : spaces.hsl ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : spaces.lab ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : {c: 0, m: 0, y: 0, k: 1}; + spaces.cmyk.c = _clip(spaces.cmyk.c); + spaces.cmyk.m = _clip(spaces.cmyk.m); + spaces.cmyk.y = _clip(spaces.cmyk.y); + spaces.cmyk.k = _clip(spaces.cmyk.k); + } + return $.extend({}, spaces.cmyk); + }; + + this.getLAB = function() { + if (!spaces.lab) { + spaces.lab = spaces.rgb ? _xyz_to_lab(_rgb_to_xyz(spaces.rgb)) + : spaces.hsv ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : spaces.hsl ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : spaces.cmyk ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : {l: 0, a: 0, b: 0}; + spaces.lab.l = _clip(spaces.lab.l); + spaces.lab.a = _clip(spaces.lab.a); + spaces.lab.b = _clip(spaces.lab.b); + } + return $.extend({}, spaces.lab); + }; + + this.getChannels = function() { + return { + r: this.getRGB().r, + g: this.getRGB().g, + b: this.getRGB().b, + a: this.getAlpha(), + h: this.getHSV().h, + s: this.getHSV().s, + v: this.getHSV().v, + c: this.getCMYK().c, + m: this.getCMYK().m, + y: this.getCMYK().y, + k: this.getCMYK().k, + L: this.getLAB().l, + A: this.getLAB().a, + B: this.getLAB().b + }; + }; + + this.distance = function(color) { + var space = 'lab', + getter = 'get'+space.toUpperCase(), + a = this[getter](), + b = color[getter](), + distance = 0, + channel; + + for (channel in a) { + distance += Math.pow(a[channel] - b[channel], 2); + } + + return distance; + }; + + this.equals = function(color) { + var a = this.getRGB(), + b = color.getRGB(); + + return this.getAlpha() == color.getAlpha() + && a.r == b.r + && a.g == b.g + && a.b == b.b; + }; + + this.limit = function(steps) { + steps -= 1; + var rgb = this.getRGB(); + this.setRGB( + Math.round(rgb.r * steps) / steps, + Math.round(rgb.g * steps) / steps, + Math.round(rgb.b * steps) / steps + ); + }; + + this.toHex = function() { + var rgb = this.getRGB(); + return _hexify(rgb.r * 255) + _hexify(rgb.g * 255) + _hexify(rgb.b * 255); + }; + + this.toCSS = function() { + return '#' + this.toHex(); + }; + + this.normalize = function() { + this.setHSV(null, 1, 1); + return this; + }; + + this.copy = function() { + var rgb = this.getRGB(), + a = this.getAlpha(); + return new Color(rgb.r, rgb.g, rgb.b, a); + }; + + // Construct + if (args.length > 0) { + this.setRGB(args[0], args[1], args[2]); + this.setAlpha(args[3] === 0 ? 0 : args[3] || 1); + } + }; + + $.widget("vanderlee.colorpicker", { + options: { + alpha: false, // Show alpha controls and mode + altAlpha: true, // change opacity of altField as well? + altField: '', // selector for DOM elements which change background color on change. + altOnChange: true, // true to update on each change, false to update only on close. + altProperties: 'background-color', // comma separated list of any of 'background-color', 'color', 'border-color', 'outline-color' + autoOpen: false, // Open dialog automatically upon creation + buttonColorize: false, + buttonImage: 'images/ui-colorpicker.png', + buttonImageOnly: false, + buttonText: null, // Text on the button and/or title of button image. + closeOnEscape: true, // Close the dialog when the escape key is pressed. + closeOnOutside: true, // Close the dialog when clicking outside the dialog (not for inline) + color: '#00FF00', // Initial color (for inline only) + colorFormat: 'HEX', // Format string for output color format + draggable: true, // Make popup dialog draggable if header is visible. + duration: 'fast', + hsv: true, // Show HSV controls and modes + regional: '', + layout: { + map: [0, 0, 1, 5], // Left, Top, Width, Height (in table cells). + bar: [1, 0, 1, 5], + preview: [2, 0, 1, 1], + hsv: [2, 1, 1, 1], + rgb: [2, 2, 1, 1], + alpha: [2, 3, 1, 1], + hex: [2, 4, 1, 1], + lab: [3, 1, 1, 1], + cmyk: [3, 2, 1, 2], + swatches: [4, 0, 1, 5] + }, + limit: '', // Limit color "resolution": '', 'websafe', 'nibble', 'binary', 'name' + modal: false, // Modal dialog? + mode: 'h', // Initial editing mode, h, s, v, r, g, b or a + parts: '', // leave empty for automatic selection + rgb: true, // Show RGB controls and modes + showAnim: 'fadeIn', + showCancelButton: true, + showNoneButton: false, + showCloseButton: true, + showOn: 'focus', // 'focus', 'button', 'both' + showOptions: {}, + swatches: null, + title: null, + + close: null, + init: null, + select: null, + open: null + }, + + _create: function () { + var that = this, + text; + + ++_colorpicker_index; + + that.widgetEventPrefix = 'color'; + + that.opened = false; + that.generated = false; + that.inline = false; + that.changed = false; + + that.dialog = null; + that.button = null; + that.image = null; + that.overlay = null; + + that.mode = that.options.mode; + + if (that.options.swatches === null) { + that.options.swatches = _colors; + } + + if (this.element[0].nodeName.toLowerCase() === 'input' || !this.inline) { + that._setColor(that.element.val()); + + this._callback('init'); + + $('body').append(_container_popup); + that.dialog = $('.ui-colorpicker:last'); + + // Click outside/inside + $(document).mousedown(function (event) { + if (!that.opened || event.target === that.element[0] || that.overlay) { + return; + } + + // Check if clicked on any part of dialog + if (that.dialog.is(event.target) || that.dialog.has(event.target).length > 0) { + that.element.blur(); // inside window! + return; + } + + // Check if clicked on button + var p, + parents = $(event.target).parents(); + for (p = 0; p <= parents.length; ++p) { + if (that.button !== null && parents[p] === that.button[0]) { + return; + } + } + + // no closeOnOutside + if (!that.options.closeOnOutside) { + return; + } + + that.close(); + }); + + $(document).keydown(function (event) { + if (event.keyCode == 27 && that.opened && that.options.closeOnEscape) { + that.close(); + } + }); + + if (that.options.showOn === 'focus' || that.options.showOn === 'both') { + that.element.focus(function () { + that.open(); + }); + } + if (that.options.showOn === 'button' || that.options.showOn === 'both') { + if (that.options.buttonImage !== '') { + text = that.options.buttonText || that._getRegional('button'); + + that.image = $('').attr({ + 'src': that.options.buttonImage, + 'alt': text, + 'title': text + }); + + that._setImageBackground(); + } + + if (that.options.buttonImageOnly && that.image) { + that.button = that.image; + } else { + that.button = $('').html(that.image || that.options.buttonText).button(); + that.image = that.image ? $('img', that.button).first() : null; + } + that.button.insertAfter(that.element).click(function () { + that[that.opened ? 'close' : 'open'](); + }); + } + + if (that.options.autoOpen) { + that.open(); + } + + that.element.keydown(function (event) { + if (event.keyCode === 9) { + that.close(); + } + }).keyup(function (event) { + var color = _parseColor(that.element.val()); + if (!that.color.equals(color)) { + that.color = color; + that._change(); + } + }); + } else { + that.inline = true; + + $(this.element).html(_container_inline); + that.dialog = $('.ui-colorpicker', this.element); + + that._generate(); + + that.opened = true; + } + + return this; + }, + + _setOption: function(key, value){ + var that = this; + + switch (key) { + case "disabled": + if (value) { + that.dialog.addClass('ui-colorpicker-disabled'); + } else { + that.dialog.removeClass('ui-colorpicker-disabled'); + } + break; + } + + $.Widget.prototype._setOption.apply(that, arguments); + }, + + /* setBackground */ + _setImageBackground: function() { + if (this.image && this.options.buttonColorize) { + this.image.css('background-color', this.color.set? _formatColor('RGBA', this.color) : ''); + } + }, + + /** + * If an alternate field is specified, set it according to the current color. + */ + _setAltField: function () { + if (this.options.altOnChange && this.options.altField && this.options.altProperties) { + var index, + property, + properties = this.options.altProperties.split(','); + + for (index = 0; index <= properties.length; ++index) { + property = $.trim(properties[index]); + switch (property) { + case 'color': + case 'background-color': + case 'outline-color': + case 'border-color': + $(this.options.altField).css(property, this.color.set? this.color.toCSS() : ''); + break; + } + } + + if (this.options.altAlpha) { + $(this.options.altField).css('opacity', this.color.set? this.color.getAlpha() : ''); + } + } + }, + + _setColor: function(text) { + this.color = _parseColor(text); + this.currentColor = this.color.copy(); + + this._setImageBackground(); + this._setAltField(); + }, + + setColor: function(text) { + this._setColor(text); + this._change(this.color.set); + }, + + _generate: function () { + var that = this, + index, + part, + parts_list, + layout_parts; + + // Set color based on element? + that._setColor(that.inline? that.options.color : that.element.val()); + + // Determine the parts to include in this colorpicker + if (typeof that.options.parts === 'string') { + if (_parts_lists[that.options.parts]) { + parts_list = _parts_lists[that.options.parts]; + } else { + // automatic + parts_list = _parts_lists[that.inline ? 'inline' : 'popup']; + } + } else { + parts_list = that.options.parts; + } + + // Add any parts to the internal parts list + that.parts = {}; + $.each(parts_list, function(index, part) { + if (_parts[part]) { + that.parts[part] = new _parts[part](that); + } + }); + + if (!that.generated) { + layout_parts = []; + + $.each(that.options.layout, function(part, pos) { + if (that.parts[part]) { + layout_parts.push({ + 'part': part, + 'pos': pos + }); + } + }); + + $(_layoutTable(layout_parts, function(cell, x, y) { + var classes = ['ui-colorpicker-' + cell.part + '-container']; + + if (x > 0) { + classes.push('ui-colorpicker-padding-left'); + } + + if (y > 0) { + classes.push('ui-colorpicker-padding-top'); + } + + return ' 1 ? ' colspan="' + cell.pos[2] + '"' : '') + + (cell.pos[3] > 1 ? ' rowspan="' + cell.pos[3] + '"' : '') + + ' valign="top">'; + })).appendTo(that.dialog).addClass('ui-dialog-content ui-widget-content'); + + that._initAllParts(); + that._updateAllParts(); + that.generated = true; + } + }, + + _effectGeneric: function (element, show, slide, fade, callback) { + var that = this; + + if ($.effects && $.effects[that.options.showAnim]) { + element[show](that.options.showAnim, that.options.showOptions, that.options.duration, callback); + } else { + element[(that.options.showAnim === 'slideDown' ? + slide + : (that.options.showAnim === 'fadeIn' ? + fade + : show))]((that.options.showAnim ? that.options.duration : null), callback); + if (!that.options.showAnim || !that.options.duration) { + callback(); + } + } + }, + + _effectShow: function(element, callback) { + this._effectGeneric(element, 'show', 'slideDown', 'fadeIn', callback); + }, + + _effectHide: function(element, callback) { + this._effectGeneric(element, 'hide', 'slideUp', 'fadeOut', callback); + }, + + open: function() { + var that = this, + offset, + bottom, + right, + height, + width, + x, + y, + zIndex; + + if (!that.opened) { + that._generate(); + + offset = that.element.offset(); + bottom = $(window).height() + $(window).scrollTop(); + right = $(window).width() + $(window).scrollLeft(); + height = that.dialog.outerHeight(); + width = that.dialog.outerWidth(); + x = offset.left; + y = offset.top + that.element.outerHeight(); + + if (x + width > right) { + x = Math.max(0, right - width); + } + + if (y + height > bottom) { + if (offset.top - height >= $(window).scrollTop()) { + y = offset.top - height; + } else { + y = Math.max(0, bottom - height); + } + } + + that.dialog.css({'left': x, 'top': y}); + + // Automatically find highest z-index. + zIndex = 0; + $(that.element[0]).parents().each(function() { + var z = $(this).css('z-index'); + if ((typeof(z) === 'number' || typeof(z) === 'string') && z !== '' && !isNaN(z)) { + zIndex = z; + return false; + } + }); + + //@todo zIndexOffset option, to raise above other elements? + that.dialog.css('z-index', zIndex += 2); + + that.overlay = that.options.modal ? new $.ui.dialog.overlay(that) : null; + + that._effectShow(this.dialog); + that.opened = true; + that._callback('open', true); + + // Without waiting for domready the width of the map is 0 and we + // wind up with the cursor stuck in the upper left corner + $(function() { + that._repaintAllParts(); + }); + } + }, + + close: function () { + var that = this; + + that.currentColor = that.color.copy(); + that.changed = false; + + // tear down the interface + that._effectHide(that.dialog, function () { + that.dialog.empty(); + that.generated = false; + + that.opened = false; + that._callback('close', true); + }); + + if (that.overlay) { + that.overlay.destroy(); + } + }, + + destroy: function() { + this.element.unbind(); + + if (this.image !== null) { + this.image.remove(); + } + + if (this.button !== null) { + this.button.remove(); + } + + if (this.dialog !== null) { + this.dialog.remove(); + } + + if (this.overlay) { + this.overlay.destroy(); + } + }, + + _callback: function (callback, spaces) { + var that = this, + data, + lab; + + if (that.color.set) { + data = { + formatted: _formatColor(that.options.colorFormat, that.color) + }; + + lab = that.color.getLAB(); + lab.a = (lab.a * 2) - 1; + lab.b = (lab.b * 2) - 1; + + if (spaces === true) { + data.a = that.color.getAlpha(); + data.rgb = that.color.getRGB(); + data.hsv = that.color.getHSV(); + data.cmyk = that.color.getCMYK(); + data.hsl = that.color.getHSL(); + data.lab = lab; + } + + return that._trigger(callback, null, data); + } else { + return that._trigger(callback, null, { + formatted: '' + }); + } + }, + + _initAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.init) { + part.init(); + } + }); + }, + + _updateAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.update) { + part.update(); + } + }); + }, + + _repaintAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.repaint) { + part.repaint(); + } + }); + }, + + _change: function (set /* = true */) { + this.color.set = (set !== false); + + this.changed = true; + + // Limit color palette + switch (this.options.limit) { + case 'websafe': + this.color.limit(6); + break; + + case 'nibble': + this.color.limit(16); + break; + + case 'binary': + this.color.limit(2); + break; + + case 'name': + var name = _closestName(this.color); + this.color.setRGB(_colors[name].r, _colors[name].g, _colors[name].b); + break; + } + + // update input element content + if (!this.inline) { + if (!this.color.set) { + this.element.val(''); + } else if (!this.color.equals(_parseColor(this.element.val()))) { + this.element.val(_formatColor(this.options.colorFormat, this.color)); + } + + this._setImageBackground(); + this._setAltField(); + } + + if (this.opened) { + this._repaintAllParts(); + } + + // callback + this._callback('select'); + }, + + // This will be deprecated by jQueryUI 1.9 widget + _hoverable: function (e) { + e.hover(function () { + e.addClass("ui-state-hover"); + }, function () { + e.removeClass("ui-state-hover"); + }); + }, + + // This will be deprecated by jQueryUI 1.9 widget + _focusable: function (e) { + e.focus(function () { + e.addClass("ui-state-focus"); + }).blur(function () { + e.removeClass("ui-state-focus"); + }); + }, + + _getRegional: function(name) { + return $.colorpicker.regional[this.options.regional][name] !== undefined ? + $.colorpicker.regional[this.options.regional][name] : $.colorpicker.regional[''][name]; + } + }); +}(jQuery)); \ No newline at end of file diff --git a/js/min/crayon.min.js b/js/min/crayon.min.js new file mode 100644 index 0000000..daa8117 --- /dev/null +++ b/js/min/crayon.min.js @@ -0,0 +1 @@ +var jQueryCrayon=jQuery;(function(a){CrayonUtil=new function(){var c=this;var b=null;c.init=function(){b=CrayonSyntaxSettings;c.initGET()};c.addPrefixToID=function(d){return d.replace(/^([#.])?(.*)$/,"$1"+b.prefix+"$2")};c.removePrefixFromID=function(e){var d=new RegExp("^[#.]?"+b.prefix,"i");return e.replace(d,"")};c.cssElem=function(d){return a(c.addPrefixToID(d))};c.setDefault=function(e,f){return(typeof e=="undefined")?f:e};c.setMax=function(e,d){return e<=d?e:d};c.setMin=function(d,e){return d>=e?d:e};c.setRange=function(e,f,d){return c.setMax(c.setMin(e,f),d)};c.getExt=function(e){if(e.indexOf(".")==-1){return undefined}var d=e.split(".");if(d.length){d=d[d.length-1]}else{d=""}return d};c.initGET=function(){window.currentURL=window.location.protocol+"//"+window.location.host+window.location.pathname;window.currentDir=window.currentURL.substring(0,window.currentURL.lastIndexOf("/"));function d(e){e=e.split("+").join(" ");var h={},g,f=/[?&]?([^=]+)=([^&]*)/g;while(g=f.exec(e)){h[decodeURIComponent(g[1])]=decodeURIComponent(g[2])}return h}window.GET=d(document.location.search)};c.getAJAX=function(d,e){d.version=b.version;a.get(b.ajaxurl,d,e)};c.postAJAX=function(d,e){d.version=b.version;a.post(b.ajaxurl,d,e)};c.reload=function(){var d="?";for(var e in window.GET){d+=e+"="+window.GET[e]+"&"}window.location=window.currentURL+d};c.escape=function(d){if(typeof encodeURIComponent=="function"){return encodeURIComponent(d)}else{if(typeof escape!="function"){return escape(d)}else{return d}}};c.log=function(d){if(typeof console!="undefined"&&b.debug){console.log(d)}};c.decode_html=function(d){return String(d).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")};c.encode_html=function(d){return String(d).replace(/&/g,"&").replace(//g,">")};c.getReadableColor=function(g,f){f=a.extend({amount:0.5,xMulti:1,yMulti:1.5,normalizeHue:[20,180],normalizeHueXMulti:1/2.5,normalizeHueYMulti:1},f);var d=tinycolor(g);var e=d.toHsv();var i={x:e.s,y:1-e.v};i.x*=f.xMulti;i.y*=f.yMulti;if(f.normalizeHue&&e.h>f.normalizeHue[0]&&e.h":">"};return this.replace(/[&<>]/g,function(c){return b[c]||c})};String.prototype.linkify=function(b){b=typeof b!="undefined"?b:"";return this.replace(/(http(s)?:\/\/(\S)+)/gmi,'$1')};String.prototype.toTitleCase=function(){var b=this.split(/\s+/);var c="";a.each(b,function(e,d){if(d!=""){c+=d.slice(0,1).toUpperCase()+d.slice(1,d.length);if(e!=b.length-1&&b[e+1]!=""){c+=" "}}});return c}})(jQueryCrayon);jqueryPopup=Object();jqueryPopup.defaultSettings={centerBrowser:0,centerScreen:0,height:500,left:0,location:0,menubar:0,resizable:0,scrollbars:0,status:0,width:500,windowName:null,windowURL:null,top:0,toolbar:0,data:null,event:"click"};(function(a){popupWindow=function(d,c,f,b){f=typeof f!=="undefined"?f:null;b=typeof b!=="undefined"?b:null;if(typeof d=="string"){d=jQuery(d)}if(!(d instanceof jQuery)){return false}var e=jQuery.extend({},jqueryPopup.defaultSettings,c||{});d.handler=jQuery(d).bind(e.event,function(){if(f){f()}var g="height="+e.height+",width="+e.width+",toolbar="+e.toolbar+",scrollbars="+e.scrollbars+",status="+e.status+",resizable="+e.resizable+",location="+e.location+",menuBar="+e.menubar;e.windowName=e.windowName||jQuery(this).attr("name");var h=jQuery(this).attr("href");if(!e.windowURL&&!(h=="#")&&!(h=="")){e.windowURL=jQuery(this).attr("href")}var i,j;var k=null;if(e.centerBrowser){if(typeof window.screenY=="undefined"){i=(window.screenTop-120)+((((document.documentElement.clientHeight+120)/2)-(e.height/2)));j=window.screenLeft+((((document.body.offsetWidth+20)/2)-(e.width/2)))}else{i=window.screenY+(((window.outerHeight/2)-(e.height/2)));j=window.screenX+(((window.outerWidth/2)-(e.width/2)))}k=window.open(e.windowURL,e.windowName,g+",left="+j+",top="+i)}else{if(e.centerScreen){i=(screen.height-e.height)/2;j=(screen.width-e.width)/2;k=window.open(e.windowURL,e.windowName,g+",left="+j+",top="+i)}else{k=window.open(e.windowURL,e.windowName,g+",left="+e.left+",top="+e.top)}}if(k!=null){k.focus();if(e.data){k.document.write(e.data)}}if(b){b()}});return e};popdownWindow=function(b,c){if(typeof c=="undefined"){c="click"}b=jQuery(b);if(!(b instanceof jQuery)){return false}b.unbind(c,b.handler)}})(jQueryCrayon);(function(f){f.fn.exists=function(){return this.length!==0};f.fn.style=function(B,E,A){var D=this.get(0);if(typeof D=="undefined"){return}var C=D.style;if(typeof B!="undefined"){if(typeof E!="undefined"){A=typeof A!="undefined"?A:"";if(typeof C.setProperty!="undefined"){C.setProperty(B,E,A)}else{C[B]=E}}else{return C[B]}}else{return C}};var d="crayon-pressed";var a="";var n="div.crayon-syntax";var e=".crayon-toolbar";var c=".crayon-info";var w=".crayon-plain";var o=".crayon-main";var m=".crayon-table";var v=".crayon-loading";var h=".crayon-code";var p=".crayon-title";var l=".crayon-tools";var b=".crayon-nums";var j=".crayon-num";var q=".crayon-line";var g="crayon-wrapped";var s=".crayon-nums-content";var u=".crayon-nums-button";var k=".crayon-wrap-button";var i=".crayon-expand-button";var t="crayon-expanded crayon-toolbar-visible";var y="crayon-placeholder";var x=".crayon-popup-button";var r=".crayon-copy-button";var z=".crayon-plain-button";CrayonSyntax=new function(){var I=this;var N=new Object();var ag;var H;var G=0;var Z;I.init=function(){if(typeof N=="undefined"){N=new Object()}ag=CrayonSyntaxSettings;H=CrayonSyntaxStrings;f(n).each(function(){I.process(this)})};I.process=function(aD,aE){aD=f(aD);var ar=aD.attr("id");if(ar=="crayon-"){ar+=X()}aD.attr("id",ar);CrayonUtil.log(ar);if(typeof aE=="undefined"){aE=false}if(!aE&&!aa(ar)){return}var au=aD.find(e);var aC=aD.find(c);var ap=aD.find(w);var aq=aD.find(o);var aB=aD.find(m);var aj=aD.find(h);var aG=aD.find(p);var aA=aD.find(l);var ay=aD.find(b);var av=aD.find(s);var az=aD.find(u);var am=aD.find(k);var ao=aD.find(i);var aF=aD.find(x);var at=aD.find(r);var al=aD.find(z);N[ar]=aD;N[ar].toolbar=au;N[ar].plain=ap;N[ar].info=aC;N[ar].main=aq;N[ar].table=aB;N[ar].code=aj;N[ar].title=aG;N[ar].tools=aA;N[ar].nums=ay;N[ar].nums_content=av;N[ar].numsButton=az;N[ar].wrapButton=am;N[ar].expandButton=ao;N[ar].popup_button=aF;N[ar].copy_button=at;N[ar].plainButton=al;N[ar].numsVisible=true;N[ar].wrapped=false;N[ar].plainVisible=false;N[ar].toolbar_delay=0;N[ar].time=1;f(w).css("z-index",0);var aw=aq.style();N[ar].mainStyle={height:aw&&aw.height||"","max-height":aw&&aw.maxHeight||"","min-height":aw&&aw.minHeight||"",width:aw&&aw.width||"","max-width":aw&&aw.maxWidth||"","min-width":aw&&aw.minWidth||""};N[ar].mainHeightAuto=N[ar].mainStyle.height==""&&N[ar].mainStyle["max-height"]=="";var ak;var ax=0;N[ar].loading=true;N[ar].scrollBlockFix=false;az.click(function(){CrayonSyntax.toggleNums(ar)});am.click(function(){CrayonSyntax.toggleWrap(ar)});ao.click(function(){CrayonSyntax.toggleExpand(ar)});al.click(function(){CrayonSyntax.togglePlain(ar)});at.click(function(){CrayonSyntax.copyPlain(ar)});B(ar);var an=function(){if(ay.filter('[data-settings~="hide"]').length!=0){av.ready(function(){CrayonUtil.log("function"+ar);CrayonSyntax.toggleNums(ar,true,true)})}else{ac(ar)}if(typeof N[ar].expanded=="undefined"){if(Math.abs(N[ar].main.outerWidth()-N[ar].table.outerWidth())<10){N[ar].expandButton.hide()}else{N[ar].expandButton.show()}}if(ax==5){clearInterval(ak);N[ar].loading=false}ax++};ak=setInterval(an,300);C(ar);f(j,N[ar]).each(function(){var aJ=f(this).attr("data-line");var aI=f("#"+aJ);var aH=aI.style("height");if(aH){aI.attr("data-height",aH)}});aq.css("position","relative");aq.css("z-index",1);Z=(aD.filter('[data-settings~="touchscreen"]').length!=0);if(!Z){aq.click(function(){A(ar,"",false)});ap.click(function(){A(ar,"",false)});aC.click(function(){A(ar,"",false)})}if(aD.filter('[data-settings~="no-popup"]').length==0){N[ar].popup_settings=popupWindow(aF,{height:screen.height-200,width:screen.width-100,top:75,left:50,scrollbars:1,windowURL:"",data:""},function(){F(ar)},function(){})}ap.css("opacity",0);N[ar].toolbarVisible=true;N[ar].hasOneLine=aB.outerHeight()
'+I.removeCssInline(I.getHtmlString(ak))+"
"};I.minimize=function(al){var ak=f('
');N[al].tools.append(ak);N[al].origTitle=N[al].title.html();if(!N[al].origTitle){N[al].title.html(H.minimize)}var aj="crayon-minimized";var ai=function(){N[al].toolbarPreventHide=false;ak.remove();N[al].removeClass(aj);N[al].title.html(N[al].origTitle);var am=N[al].toolbar;if(am.filter('[data-settings~="never-show"]').length!=0){am.remove()}};N[al].toolbar.click(ai);ak.click(ai);N[al].addClass(aj);N[al].toolbarPreventHide=true;T(al,undefined,undefined,0)};I.getHtmlString=function(ai){return f("
").append(ai.clone()).remove().html()};I.removeCssInline=function(ak){var aj=/style\s*=\s*"([^"]+)"/gmi;var ai=null;while((ai=aj.exec(ak))!=null){var al=ai[1];al=al.replace(/\b(?:width|height)\s*:[^;]+;/gmi,"");ak=ak.sliceReplace(ai.index,ai.index+ai[0].length,'style="'+al+'"')}return ak};I.getAllCSS=function(){var ak="";var aj=f('link[rel="stylesheet"]');var ai=[];if(aj.length==1){ai=aj}else{ai=aj.filter('[href*="crayon-syntax-highlighter"], [href*="min/"]')}ai.each(function(){var al=I.getHtmlString(f(this));ak+=al});return ak};I.copyPlain=function(ak,al){if(typeof N[ak]=="undefined"){return aa(ak)}var aj=N[ak].plain;I.togglePlain(ak,true,true);T(ak,true);var ai=N[ak].mac?"\u2318":"CTRL";var am=H.copy;am=am.replace(/%s/,ai+"+C");am=am.replace(/%s/,ai+"+V");A(ak,am);return false};var A=function(aj,al,ai){if(typeof N[aj]=="undefined"){return aa(aj)}var ak=N[aj].info;if(typeof al=="undefined"){al=""}if(typeof ai=="undefined"){ai=true}if(L(ak)&&ai){ak.html("
"+al+"
");ak.css("margin-top",-ak.outerHeight());ak.show();Q(aj,ak,true);setTimeout(function(){Q(aj,ak,false)},5000)}if(!ai){Q(aj,ak,false)}};var B=function(ai){if(window.devicePixelRatio>1){var aj=f(".crayon-button-icon",N[ai].toolbar);aj.each(function(){var al=f(this).css("background-image");var ak=al.replace(/\.(?=[^\.]+$)/g,"@2x.");f(this).css("background-size","48px 128px");f(this).css("background-image",ak)})}};var L=function(ai){var aj="-"+ai.outerHeight()+"px";if(ai.css("margin-top")==aj||ai.css("display")=="none"){return true}else{return false}};var Q=function(al,ak,aj,an,am,ap){var ai=function(){if(ap){ap(al,ak)}};var ao="-"+ak.outerHeight()+"px";if(typeof aj=="undefined"){if(L(ak)){aj=true}else{aj=false}}if(typeof an=="undefined"){an=100}if(an==false){an=false}if(typeof am=="undefined"){am=0}ak.stop(true);if(aj==true){ak.show();ak.animate({marginTop:0},ah(an,al),ai)}else{if(aj==false){if(ak.css("margin-top")=="0px"&&am){ak.delay(am)}ak.animate({marginTop:ao},ah(an,al),function(){ak.hide();ai()})}}};I.togglePlain=function(al,am,aj){if(typeof N[al]=="undefined"){return aa(al)}var ai=N[al].main;var ak=N[al].plain;if((ai.is(":animated")||ak.is(":animated"))&&typeof am=="undefined"){return}ae(al);var ao,an;if(typeof am!="undefined"){if(am){ao=ai;an=ak}else{ao=ak;an=ai}}else{if(ai.css("z-index")==1){ao=ai;an=ak}else{ao=ak;an=ai}}N[al].plainVisible=(an==ak);N[al].top=ao.scrollTop();N[al].left=ao.scrollLeft();N[al].scrollChanged=false;C(al);ao.stop(true);ao.fadeTo(ah(500,al),0,function(){ao.css("z-index",0)});an.stop(true);an.fadeTo(ah(500,al),1,function(){an.css("z-index",1);if(an==ak){if(aj){ak.select()}else{}}an.scrollTop(N[al].top+1);an.scrollTop(N[al].top);an.scrollLeft(N[al].left+1);an.scrollLeft(N[al].left)});an.scrollTop(N[al].top);an.scrollLeft(N[al].left);ab(al);T(al,false);return false};I.toggleNums=function(am,al,ai){if(typeof N[am]=="undefined"){aa(am);return false}if(N[am].table.is(":animated")){return false}var ao=Math.round(N[am].nums_content.outerWidth()+1);var an="-"+ao+"px";var ak;if(typeof al!="undefined"){ak=false}else{ak=(N[am].table.css("margin-left")==an)}var aj;if(ak){aj="0px";N[am].numsVisible=true}else{N[am].table.css("margin-left","0px");N[am].numsVisible=false;aj=an}if(typeof ai!="undefined"){N[am].table.css("margin-left",aj);ac(am);return false}var ap=(N[am].table.outerWidth()+J(N[am].table.css("margin-left"))>N[am].main.outerWidth());var aq=(N[am].table.outerHeight()>N[am].main.outerHeight());if(!ap&&!aq){N[am].main.css("overflow","hidden")}N[am].table.animate({marginLeft:aj},ah(200,am),function(){if(typeof N[am]!="undefined"){ac(am);if(!ap&&!aq){N[am].main.css("overflow","auto")}}});return false};I.toggleWrap=function(ai){N[ai].wrapped=!N[ai].wrapped;Y(ai)};I.toggleExpand=function(ai){var aj=!CrayonUtil.setDefault(N[ai].expanded,false);D(ai,aj)};var Y=function(ai,aj){aj=CrayonUtil.setDefault(aj,true);if(N[ai].wrapped){N[ai].addClass(g)}else{N[ai].removeClass(g)}E(ai);if(!N[ai].expanded&&aj){V(ai)}N[ai].wrapTimes=0;clearInterval(N[ai].wrapTimer);N[ai].wrapTimer=setInterval(function(){if(N[ai].is(":visible")){O(ai);N[ai].wrapTimes++;if(N[ai].wrapTimes==5){clearInterval(N[ai].wrapTimer)}}},200)};var ad=function(ai){if(typeof N[ai]=="undefined"){aa(ai);return false}};var J=function(aj){if(typeof aj!="string"){return 0}var ai=aj.replace(/[^-0-9]/g,"");if(ai.length==0){return 0}else{return parseInt(ai)}};var ac=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].numsVisible=="undefined"){return}if(N[ai].numsVisible){N[ai].numsButton.removeClass(a);N[ai].numsButton.addClass(d)}else{N[ai].numsButton.removeClass(d);N[ai].numsButton.addClass(a)}};var E=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].wrapped=="undefined"){return}if(N[ai].wrapped){N[ai].wrapButton.removeClass(a);N[ai].wrapButton.addClass(d)}else{N[ai].wrapButton.removeClass(d);N[ai].wrapButton.addClass(a)}};var W=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].expanded=="undefined"){return}if(N[ai].expanded){N[ai].expandButton.removeClass(a);N[ai].expandButton.addClass(d)}else{N[ai].expandButton.removeClass(d);N[ai].expandButton.addClass(a)}};var ab=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].plainVisible=="undefined"){return}if(N[ai].plainVisible){N[ai].plainButton.removeClass(a);N[ai].plainButton.addClass(d)}else{N[ai].plainButton.removeClass(d);N[ai].plainButton.addClass(a)}};var T=function(aj,ai,al,ak){if(typeof N[aj]=="undefined"){return aa(aj)}else{if(!N[aj].toolbarMouseover){return}else{if(ai==false&&N[aj].toolbarPreventHide){return}else{if(Z){return}}}}var am=N[aj].toolbar;if(typeof ak=="undefined"){ak=N[aj].toolbar_delay}Q(aj,am,ai,al,ak,function(){N[aj].toolbarVisible=ai})};var R=function(ak,ai){var aj=f.extend({},ak);aj.width+=ai.width;aj.height+=ai.height;return aj};var P=function(ak,ai){var aj=f.extend({},ak);aj.width-=ai.width;aj.height-=ai.height;return aj};var U=function(ai){if(typeof N[ai].initialSize=="undefined"){N[ai].toolbarHeight=N[ai].toolbar.outerHeight();N[ai].innerSize={width:N[ai].width(),height:N[ai].height()};N[ai].outerSize={width:N[ai].outerWidth(),height:N[ai].outerHeight()};N[ai].borderSize=P(N[ai].outerSize,N[ai].innerSize);N[ai].initialSize={width:N[ai].main.outerWidth(),height:N[ai].main.outerHeight()};N[ai].initialSize.height+=N[ai].toolbarHeight;N[ai].initialOuterSize=R(N[ai].initialSize,N[ai].borderSize);N[ai].finalSize={width:N[ai].table.outerWidth(),height:N[ai].table.outerHeight()};N[ai].finalSize.height+=N[ai].toolbarHeight;N[ai].finalSize.width=CrayonUtil.setMin(N[ai].finalSize.width,N[ai].initialSize.width);N[ai].finalSize.height=CrayonUtil.setMin(N[ai].finalSize.height,N[ai].initialSize.height);N[ai].diffSize=P(N[ai].finalSize,N[ai].initialSize);N[ai].finalOuterSize=R(N[ai].finalSize,N[ai].borderSize);N[ai].initialSize.height+=N[ai].toolbar.outerHeight()}};var D=function(al,ao){if(typeof N[al]=="undefined"){return aa(al)}if(typeof ao=="undefined"){return}var aj=N[al].main;var aq=N[al].plain;if(ao){if(typeof N[al].expanded=="undefined"){U(al);N[al].expandTime=CrayonUtil.setRange(N[al].diffSize.width/3,300,800);N[al].expanded=false;var ap=N[al].finalOuterSize;N[al].placeholder=f("
");N[al].placeholder.addClass(y);N[al].placeholder.css(ap);N[al].before(N[al].placeholder);N[al].placeholder.css("margin",N[al].css("margin"));f(window).bind("resize",K)}var am={height:"auto","min-height":"none","max-height":"none"};var ai={width:"auto","min-width":"none","max-width":"none"};N[al].outerWidth(N[al].outerWidth());N[al].css({"min-width":"none","max-width":"none"});var an={width:N[al].finalOuterSize.width};if(!N[al].mainHeightAuto&&!N[al].hasOneLine){an.height=N[al].finalOuterSize.height;N[al].outerHeight(N[al].outerHeight())}aj.css(am);aj.css(ai);N[al].stop(true);N[al].animate(an,ah(N[al].expandTime,al),function(){N[al].expanded=true;W(al)});N[al].placeholder.show();f("body").prepend(N[al]);N[al].addClass(t);K()}else{var ar=N[al].initialOuterSize;var ak=N[al].toolbar_delay;if(ar){N[al].stop(true);if(!N[al].expanded){N[al].delay(ak)}var an={width:ar.width};if(!N[al].mainHeightAuto&&!N[al].hasOneLine){an.height=ar.height}N[al].animate(an,ah(N[al].expandTime,al),function(){af(al)})}else{setTimeout(function(){af(al)},ak)}N[al].placeholder.hide();N[al].placeholder.before(N[al]);N[al].css({left:"auto",top:"auto"});N[al].removeClass(t)}ae(al);if(ao){Y(al,false)}};var K=function(){for(uid in N){if(N[uid].hasClass(t)){N[uid].css(N[uid].placeholder.offset())}}};var af=function(ai){N[ai].expanded=false;V(ai);W(ai);if(N[ai].wrapped){Y(ai)}};var M=function(al,aj,am){if(typeof N[al]=="undefined"){return aa(al)}if(typeof aj=="undefined"||am||N[al].expanded){return}var ai=N[al].main;var ak=N[al].plain;if(aj){ai.css("overflow","auto");ak.css("overflow","auto");if(typeof N[al].top!="undefined"){visible=(ai.css("z-index")==1?ai:ak);visible.scrollTop(N[al].top-1);visible.scrollTop(N[al].top);visible.scrollLeft(N[al].left-1);visible.scrollLeft(N[al].left)}}else{visible=(ai.css("z-index")==1?ai:ak);N[al].top=visible.scrollTop();N[al].left=visible.scrollLeft();ai.css("overflow","hidden");ak.css("overflow","hidden")}N[al].scrollChanged=true;C(al)};var C=function(ai){N[ai].table.style("width","100%","important");var aj=setTimeout(function(){N[ai].table.style("width","");clearInterval(aj)},10)};var V=function(ak){var aj=N[ak].main;var ai=N[ak].mainStyle;aj.css(ai);N[ak].css("height","auto");N[ak].css("width",ai.width);N[ak].css("max-width",ai["max-width"]);N[ak].css("min-width",ai["min-width"])};var ae=function(ai){N[ai].plain.outerHeight(N[ai].main.outerHeight())};var O=function(ai){f(j,N[ai]).each(function(){var al=f(this).attr("data-line");var ak=f("#"+al);var aj=null;if(N[ai].wrapped){ak.css("height","");aj=ak.outerHeight();aj=aj?aj:""}else{aj=ak.attr("data-height");aj=aj?aj:"";ak.css("height",aj)}f(this).css("height",aj)})};var ah=function(ai,aj){if(ai=="fast"){ai=200}else{if(ai=="slow"){ai=600}else{if(!S(ai)){ai=parseInt(ai);if(isNaN(ai)){return 0}}}}return ai*N[aj].time};var S=function(ai){return typeof ai=="number"}};f(document).ready(function(){CrayonSyntax.init()})})(jQueryCrayon); \ No newline at end of file diff --git a/js/min/crayon.te.min.js b/js/min/crayon.te.min.js new file mode 100644 index 0000000..1d85a87 --- /dev/null +++ b/js/min/crayon.te.min.js @@ -0,0 +1,8 @@ +var jQueryCrayon=jQuery;(function(a){CrayonUtil=new function(){var c=this;var b=null;c.init=function(){b=CrayonSyntaxSettings;c.initGET()};c.addPrefixToID=function(d){return d.replace(/^([#.])?(.*)$/,"$1"+b.prefix+"$2")};c.removePrefixFromID=function(e){var d=new RegExp("^[#.]?"+b.prefix,"i");return e.replace(d,"")};c.cssElem=function(d){return a(c.addPrefixToID(d))};c.setDefault=function(e,f){return(typeof e=="undefined")?f:e};c.setMax=function(e,d){return e<=d?e:d};c.setMin=function(d,e){return d>=e?d:e};c.setRange=function(e,f,d){return c.setMax(c.setMin(e,f),d)};c.getExt=function(e){if(e.indexOf(".")==-1){return undefined}var d=e.split(".");if(d.length){d=d[d.length-1]}else{d=""}return d};c.initGET=function(){window.currentURL=window.location.protocol+"//"+window.location.host+window.location.pathname;window.currentDir=window.currentURL.substring(0,window.currentURL.lastIndexOf("/"));function d(e){e=e.split("+").join(" ");var h={},g,f=/[?&]?([^=]+)=([^&]*)/g;while(g=f.exec(e)){h[decodeURIComponent(g[1])]=decodeURIComponent(g[2])}return h}window.GET=d(document.location.search)};c.getAJAX=function(d,e){d.version=b.version;a.get(b.ajaxurl,d,e)};c.postAJAX=function(d,e){d.version=b.version;a.post(b.ajaxurl,d,e)};c.reload=function(){var d="?";for(var e in window.GET){d+=e+"="+window.GET[e]+"&"}window.location=window.currentURL+d};c.escape=function(d){if(typeof encodeURIComponent=="function"){return encodeURIComponent(d)}else{if(typeof escape!="function"){return escape(d)}else{return d}}};c.log=function(d){if(typeof console!="undefined"&&b.debug){console.log(d)}};c.decode_html=function(d){return String(d).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")};c.encode_html=function(d){return String(d).replace(/&/g,"&").replace(//g,">")};c.getReadableColor=function(g,f){f=a.extend({amount:0.5,xMulti:1,yMulti:1.5,normalizeHue:[20,180],normalizeHueXMulti:1/2.5,normalizeHueYMulti:1},f);var d=tinycolor(g);var e=d.toHsv();var i={x:e.s,y:1-e.v};i.x*=f.xMulti;i.y*=f.yMulti;if(f.normalizeHue&&e.h>f.normalizeHue[0]&&e.h":">"};return this.replace(/[&<>]/g,function(c){return b[c]||c})};String.prototype.linkify=function(b){b=typeof b!="undefined"?b:"";return this.replace(/(http(s)?:\/\/(\S)+)/gmi,'$1')};String.prototype.toTitleCase=function(){var b=this.split(/\s+/);var c="";a.each(b,function(e,d){if(d!=""){c+=d.slice(0,1).toUpperCase()+d.slice(1,d.length);if(e!=b.length-1&&b[e+1]!=""){c+=" "}}});return c}})(jQueryCrayon);jqueryPopup=Object();jqueryPopup.defaultSettings={centerBrowser:0,centerScreen:0,height:500,left:0,location:0,menubar:0,resizable:0,scrollbars:0,status:0,width:500,windowName:null,windowURL:null,top:0,toolbar:0,data:null,event:"click"};(function(a){popupWindow=function(d,c,f,b){f=typeof f!=="undefined"?f:null;b=typeof b!=="undefined"?b:null;if(typeof d=="string"){d=jQuery(d)}if(!(d instanceof jQuery)){return false}var e=jQuery.extend({},jqueryPopup.defaultSettings,c||{});d.handler=jQuery(d).bind(e.event,function(){if(f){f()}var g="height="+e.height+",width="+e.width+",toolbar="+e.toolbar+",scrollbars="+e.scrollbars+",status="+e.status+",resizable="+e.resizable+",location="+e.location+",menuBar="+e.menubar;e.windowName=e.windowName||jQuery(this).attr("name");var h=jQuery(this).attr("href");if(!e.windowURL&&!(h=="#")&&!(h=="")){e.windowURL=jQuery(this).attr("href")}var i,j;var k=null;if(e.centerBrowser){if(typeof window.screenY=="undefined"){i=(window.screenTop-120)+((((document.documentElement.clientHeight+120)/2)-(e.height/2)));j=window.screenLeft+((((document.body.offsetWidth+20)/2)-(e.width/2)))}else{i=window.screenY+(((window.outerHeight/2)-(e.height/2)));j=window.screenX+(((window.outerWidth/2)-(e.width/2)))}k=window.open(e.windowURL,e.windowName,g+",left="+j+",top="+i)}else{if(e.centerScreen){i=(screen.height-e.height)/2;j=(screen.width-e.width)/2;k=window.open(e.windowURL,e.windowName,g+",left="+j+",top="+i)}else{k=window.open(e.windowURL,e.windowName,g+",left="+e.left+",top="+e.top)}}if(k!=null){k.focus();if(e.data){k.document.write(e.data)}}if(b){b()}});return e};popdownWindow=function(b,c){if(typeof c=="undefined"){c="click"}b=jQuery(b);if(!(b instanceof jQuery)){return false}b.unbind(c,b.handler)}})(jQueryCrayon);(function(f){f.fn.exists=function(){return this.length!==0};f.fn.style=function(B,E,A){var D=this.get(0);if(typeof D=="undefined"){return}var C=D.style;if(typeof B!="undefined"){if(typeof E!="undefined"){A=typeof A!="undefined"?A:"";if(typeof C.setProperty!="undefined"){C.setProperty(B,E,A)}else{C[B]=E}}else{return C[B]}}else{return C}};var d="crayon-pressed";var a="";var n="div.crayon-syntax";var e=".crayon-toolbar";var c=".crayon-info";var w=".crayon-plain";var o=".crayon-main";var m=".crayon-table";var v=".crayon-loading";var h=".crayon-code";var p=".crayon-title";var l=".crayon-tools";var b=".crayon-nums";var j=".crayon-num";var q=".crayon-line";var g="crayon-wrapped";var s=".crayon-nums-content";var u=".crayon-nums-button";var k=".crayon-wrap-button";var i=".crayon-expand-button";var t="crayon-expanded crayon-toolbar-visible";var y="crayon-placeholder";var x=".crayon-popup-button";var r=".crayon-copy-button";var z=".crayon-plain-button";CrayonSyntax=new function(){var I=this;var N=new Object();var ag;var H;var G=0;var Z;I.init=function(){if(typeof N=="undefined"){N=new Object()}ag=CrayonSyntaxSettings;H=CrayonSyntaxStrings;f(n).each(function(){I.process(this)})};I.process=function(aD,aE){aD=f(aD);var ar=aD.attr("id");if(ar=="crayon-"){ar+=X()}aD.attr("id",ar);CrayonUtil.log(ar);if(typeof aE=="undefined"){aE=false}if(!aE&&!aa(ar)){return}var au=aD.find(e);var aC=aD.find(c);var ap=aD.find(w);var aq=aD.find(o);var aB=aD.find(m);var aj=aD.find(h);var aG=aD.find(p);var aA=aD.find(l);var ay=aD.find(b);var av=aD.find(s);var az=aD.find(u);var am=aD.find(k);var ao=aD.find(i);var aF=aD.find(x);var at=aD.find(r);var al=aD.find(z);N[ar]=aD;N[ar].toolbar=au;N[ar].plain=ap;N[ar].info=aC;N[ar].main=aq;N[ar].table=aB;N[ar].code=aj;N[ar].title=aG;N[ar].tools=aA;N[ar].nums=ay;N[ar].nums_content=av;N[ar].numsButton=az;N[ar].wrapButton=am;N[ar].expandButton=ao;N[ar].popup_button=aF;N[ar].copy_button=at;N[ar].plainButton=al;N[ar].numsVisible=true;N[ar].wrapped=false;N[ar].plainVisible=false;N[ar].toolbar_delay=0;N[ar].time=1;f(w).css("z-index",0);var aw=aq.style();N[ar].mainStyle={height:aw&&aw.height||"","max-height":aw&&aw.maxHeight||"","min-height":aw&&aw.minHeight||"",width:aw&&aw.width||"","max-width":aw&&aw.maxWidth||"","min-width":aw&&aw.minWidth||""};N[ar].mainHeightAuto=N[ar].mainStyle.height==""&&N[ar].mainStyle["max-height"]=="";var ak;var ax=0;N[ar].loading=true;N[ar].scrollBlockFix=false;az.click(function(){CrayonSyntax.toggleNums(ar)});am.click(function(){CrayonSyntax.toggleWrap(ar)});ao.click(function(){CrayonSyntax.toggleExpand(ar)});al.click(function(){CrayonSyntax.togglePlain(ar)});at.click(function(){CrayonSyntax.copyPlain(ar)});B(ar);var an=function(){if(ay.filter('[data-settings~="hide"]').length!=0){av.ready(function(){CrayonUtil.log("function"+ar);CrayonSyntax.toggleNums(ar,true,true)})}else{ac(ar)}if(typeof N[ar].expanded=="undefined"){if(Math.abs(N[ar].main.outerWidth()-N[ar].table.outerWidth())<10){N[ar].expandButton.hide()}else{N[ar].expandButton.show()}}if(ax==5){clearInterval(ak);N[ar].loading=false}ax++};ak=setInterval(an,300);C(ar);f(j,N[ar]).each(function(){var aJ=f(this).attr("data-line");var aI=f("#"+aJ);var aH=aI.style("height");if(aH){aI.attr("data-height",aH)}});aq.css("position","relative");aq.css("z-index",1);Z=(aD.filter('[data-settings~="touchscreen"]').length!=0);if(!Z){aq.click(function(){A(ar,"",false)});ap.click(function(){A(ar,"",false)});aC.click(function(){A(ar,"",false)})}if(aD.filter('[data-settings~="no-popup"]').length==0){N[ar].popup_settings=popupWindow(aF,{height:screen.height-200,width:screen.width-100,top:75,left:50,scrollbars:1,windowURL:"",data:""},function(){F(ar)},function(){})}ap.css("opacity",0);N[ar].toolbarVisible=true;N[ar].hasOneLine=aB.outerHeight()
'+I.removeCssInline(I.getHtmlString(ak))+"
"};I.minimize=function(al){var ak=f('
');N[al].tools.append(ak);N[al].origTitle=N[al].title.html();if(!N[al].origTitle){N[al].title.html(H.minimize)}var aj="crayon-minimized";var ai=function(){N[al].toolbarPreventHide=false;ak.remove();N[al].removeClass(aj);N[al].title.html(N[al].origTitle);var am=N[al].toolbar;if(am.filter('[data-settings~="never-show"]').length!=0){am.remove()}};N[al].toolbar.click(ai);ak.click(ai);N[al].addClass(aj);N[al].toolbarPreventHide=true;T(al,undefined,undefined,0)};I.getHtmlString=function(ai){return f("
").append(ai.clone()).remove().html()};I.removeCssInline=function(ak){var aj=/style\s*=\s*"([^"]+)"/gmi;var ai=null;while((ai=aj.exec(ak))!=null){var al=ai[1];al=al.replace(/\b(?:width|height)\s*:[^;]+;/gmi,"");ak=ak.sliceReplace(ai.index,ai.index+ai[0].length,'style="'+al+'"')}return ak};I.getAllCSS=function(){var ak="";var aj=f('link[rel="stylesheet"]');var ai=[];if(aj.length==1){ai=aj}else{ai=aj.filter('[href*="crayon-syntax-highlighter"], [href*="min/"]')}ai.each(function(){var al=I.getHtmlString(f(this));ak+=al});return ak};I.copyPlain=function(ak,al){if(typeof N[ak]=="undefined"){return aa(ak)}var aj=N[ak].plain;I.togglePlain(ak,true,true);T(ak,true);var ai=N[ak].mac?"\u2318":"CTRL";var am=H.copy;am=am.replace(/%s/,ai+"+C");am=am.replace(/%s/,ai+"+V");A(ak,am);return false};var A=function(aj,al,ai){if(typeof N[aj]=="undefined"){return aa(aj)}var ak=N[aj].info;if(typeof al=="undefined"){al=""}if(typeof ai=="undefined"){ai=true}if(L(ak)&&ai){ak.html("
"+al+"
");ak.css("margin-top",-ak.outerHeight());ak.show();Q(aj,ak,true);setTimeout(function(){Q(aj,ak,false)},5000)}if(!ai){Q(aj,ak,false)}};var B=function(ai){if(window.devicePixelRatio>1){var aj=f(".crayon-button-icon",N[ai].toolbar);aj.each(function(){var al=f(this).css("background-image");var ak=al.replace(/\.(?=[^\.]+$)/g,"@2x.");f(this).css("background-size","48px 128px");f(this).css("background-image",ak)})}};var L=function(ai){var aj="-"+ai.outerHeight()+"px";if(ai.css("margin-top")==aj||ai.css("display")=="none"){return true}else{return false}};var Q=function(al,ak,aj,an,am,ap){var ai=function(){if(ap){ap(al,ak)}};var ao="-"+ak.outerHeight()+"px";if(typeof aj=="undefined"){if(L(ak)){aj=true}else{aj=false}}if(typeof an=="undefined"){an=100}if(an==false){an=false}if(typeof am=="undefined"){am=0}ak.stop(true);if(aj==true){ak.show();ak.animate({marginTop:0},ah(an,al),ai)}else{if(aj==false){if(ak.css("margin-top")=="0px"&&am){ak.delay(am)}ak.animate({marginTop:ao},ah(an,al),function(){ak.hide();ai()})}}};I.togglePlain=function(al,am,aj){if(typeof N[al]=="undefined"){return aa(al)}var ai=N[al].main;var ak=N[al].plain;if((ai.is(":animated")||ak.is(":animated"))&&typeof am=="undefined"){return}ae(al);var ao,an;if(typeof am!="undefined"){if(am){ao=ai;an=ak}else{ao=ak;an=ai}}else{if(ai.css("z-index")==1){ao=ai;an=ak}else{ao=ak;an=ai}}N[al].plainVisible=(an==ak);N[al].top=ao.scrollTop();N[al].left=ao.scrollLeft();N[al].scrollChanged=false;C(al);ao.stop(true);ao.fadeTo(ah(500,al),0,function(){ao.css("z-index",0)});an.stop(true);an.fadeTo(ah(500,al),1,function(){an.css("z-index",1);if(an==ak){if(aj){ak.select()}else{}}an.scrollTop(N[al].top+1);an.scrollTop(N[al].top);an.scrollLeft(N[al].left+1);an.scrollLeft(N[al].left)});an.scrollTop(N[al].top);an.scrollLeft(N[al].left);ab(al);T(al,false);return false};I.toggleNums=function(am,al,ai){if(typeof N[am]=="undefined"){aa(am);return false}if(N[am].table.is(":animated")){return false}var ao=Math.round(N[am].nums_content.outerWidth()+1);var an="-"+ao+"px";var ak;if(typeof al!="undefined"){ak=false}else{ak=(N[am].table.css("margin-left")==an)}var aj;if(ak){aj="0px";N[am].numsVisible=true}else{N[am].table.css("margin-left","0px");N[am].numsVisible=false;aj=an}if(typeof ai!="undefined"){N[am].table.css("margin-left",aj);ac(am);return false}var ap=(N[am].table.outerWidth()+J(N[am].table.css("margin-left"))>N[am].main.outerWidth());var aq=(N[am].table.outerHeight()>N[am].main.outerHeight());if(!ap&&!aq){N[am].main.css("overflow","hidden")}N[am].table.animate({marginLeft:aj},ah(200,am),function(){if(typeof N[am]!="undefined"){ac(am);if(!ap&&!aq){N[am].main.css("overflow","auto")}}});return false};I.toggleWrap=function(ai){N[ai].wrapped=!N[ai].wrapped;Y(ai)};I.toggleExpand=function(ai){var aj=!CrayonUtil.setDefault(N[ai].expanded,false);D(ai,aj)};var Y=function(ai,aj){aj=CrayonUtil.setDefault(aj,true);if(N[ai].wrapped){N[ai].addClass(g)}else{N[ai].removeClass(g)}E(ai);if(!N[ai].expanded&&aj){V(ai)}N[ai].wrapTimes=0;clearInterval(N[ai].wrapTimer);N[ai].wrapTimer=setInterval(function(){if(N[ai].is(":visible")){O(ai);N[ai].wrapTimes++;if(N[ai].wrapTimes==5){clearInterval(N[ai].wrapTimer)}}},200)};var ad=function(ai){if(typeof N[ai]=="undefined"){aa(ai);return false}};var J=function(aj){if(typeof aj!="string"){return 0}var ai=aj.replace(/[^-0-9]/g,"");if(ai.length==0){return 0}else{return parseInt(ai)}};var ac=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].numsVisible=="undefined"){return}if(N[ai].numsVisible){N[ai].numsButton.removeClass(a);N[ai].numsButton.addClass(d)}else{N[ai].numsButton.removeClass(d);N[ai].numsButton.addClass(a)}};var E=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].wrapped=="undefined"){return}if(N[ai].wrapped){N[ai].wrapButton.removeClass(a);N[ai].wrapButton.addClass(d)}else{N[ai].wrapButton.removeClass(d);N[ai].wrapButton.addClass(a)}};var W=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].expanded=="undefined"){return}if(N[ai].expanded){N[ai].expandButton.removeClass(a);N[ai].expandButton.addClass(d)}else{N[ai].expandButton.removeClass(d);N[ai].expandButton.addClass(a)}};var ab=function(ai){if(typeof N[ai]=="undefined"||typeof N[ai].plainVisible=="undefined"){return}if(N[ai].plainVisible){N[ai].plainButton.removeClass(a);N[ai].plainButton.addClass(d)}else{N[ai].plainButton.removeClass(d);N[ai].plainButton.addClass(a)}};var T=function(aj,ai,al,ak){if(typeof N[aj]=="undefined"){return aa(aj)}else{if(!N[aj].toolbarMouseover){return}else{if(ai==false&&N[aj].toolbarPreventHide){return}else{if(Z){return}}}}var am=N[aj].toolbar;if(typeof ak=="undefined"){ak=N[aj].toolbar_delay}Q(aj,am,ai,al,ak,function(){N[aj].toolbarVisible=ai})};var R=function(ak,ai){var aj=f.extend({},ak);aj.width+=ai.width;aj.height+=ai.height;return aj};var P=function(ak,ai){var aj=f.extend({},ak);aj.width-=ai.width;aj.height-=ai.height;return aj};var U=function(ai){if(typeof N[ai].initialSize=="undefined"){N[ai].toolbarHeight=N[ai].toolbar.outerHeight();N[ai].innerSize={width:N[ai].width(),height:N[ai].height()};N[ai].outerSize={width:N[ai].outerWidth(),height:N[ai].outerHeight()};N[ai].borderSize=P(N[ai].outerSize,N[ai].innerSize);N[ai].initialSize={width:N[ai].main.outerWidth(),height:N[ai].main.outerHeight()};N[ai].initialSize.height+=N[ai].toolbarHeight;N[ai].initialOuterSize=R(N[ai].initialSize,N[ai].borderSize);N[ai].finalSize={width:N[ai].table.outerWidth(),height:N[ai].table.outerHeight()};N[ai].finalSize.height+=N[ai].toolbarHeight;N[ai].finalSize.width=CrayonUtil.setMin(N[ai].finalSize.width,N[ai].initialSize.width);N[ai].finalSize.height=CrayonUtil.setMin(N[ai].finalSize.height,N[ai].initialSize.height);N[ai].diffSize=P(N[ai].finalSize,N[ai].initialSize);N[ai].finalOuterSize=R(N[ai].finalSize,N[ai].borderSize);N[ai].initialSize.height+=N[ai].toolbar.outerHeight()}};var D=function(al,ao){if(typeof N[al]=="undefined"){return aa(al)}if(typeof ao=="undefined"){return}var aj=N[al].main;var aq=N[al].plain;if(ao){if(typeof N[al].expanded=="undefined"){U(al);N[al].expandTime=CrayonUtil.setRange(N[al].diffSize.width/3,300,800);N[al].expanded=false;var ap=N[al].finalOuterSize;N[al].placeholder=f("
");N[al].placeholder.addClass(y);N[al].placeholder.css(ap);N[al].before(N[al].placeholder);N[al].placeholder.css("margin",N[al].css("margin"));f(window).bind("resize",K)}var am={height:"auto","min-height":"none","max-height":"none"};var ai={width:"auto","min-width":"none","max-width":"none"};N[al].outerWidth(N[al].outerWidth());N[al].css({"min-width":"none","max-width":"none"});var an={width:N[al].finalOuterSize.width};if(!N[al].mainHeightAuto&&!N[al].hasOneLine){an.height=N[al].finalOuterSize.height;N[al].outerHeight(N[al].outerHeight())}aj.css(am);aj.css(ai);N[al].stop(true);N[al].animate(an,ah(N[al].expandTime,al),function(){N[al].expanded=true;W(al)});N[al].placeholder.show();f("body").prepend(N[al]);N[al].addClass(t);K()}else{var ar=N[al].initialOuterSize;var ak=N[al].toolbar_delay;if(ar){N[al].stop(true);if(!N[al].expanded){N[al].delay(ak)}var an={width:ar.width};if(!N[al].mainHeightAuto&&!N[al].hasOneLine){an.height=ar.height}N[al].animate(an,ah(N[al].expandTime,al),function(){af(al)})}else{setTimeout(function(){af(al)},ak)}N[al].placeholder.hide();N[al].placeholder.before(N[al]);N[al].css({left:"auto",top:"auto"});N[al].removeClass(t)}ae(al);if(ao){Y(al,false)}};var K=function(){for(uid in N){if(N[uid].hasClass(t)){N[uid].css(N[uid].placeholder.offset())}}};var af=function(ai){N[ai].expanded=false;V(ai);W(ai);if(N[ai].wrapped){Y(ai)}};var M=function(al,aj,am){if(typeof N[al]=="undefined"){return aa(al)}if(typeof aj=="undefined"||am||N[al].expanded){return}var ai=N[al].main;var ak=N[al].plain;if(aj){ai.css("overflow","auto");ak.css("overflow","auto");if(typeof N[al].top!="undefined"){visible=(ai.css("z-index")==1?ai:ak);visible.scrollTop(N[al].top-1);visible.scrollTop(N[al].top);visible.scrollLeft(N[al].left-1);visible.scrollLeft(N[al].left)}}else{visible=(ai.css("z-index")==1?ai:ak);N[al].top=visible.scrollTop();N[al].left=visible.scrollLeft();ai.css("overflow","hidden");ak.css("overflow","hidden")}N[al].scrollChanged=true;C(al)};var C=function(ai){N[ai].table.style("width","100%","important");var aj=setTimeout(function(){N[ai].table.style("width","");clearInterval(aj)},10)};var V=function(ak){var aj=N[ak].main;var ai=N[ak].mainStyle;aj.css(ai);N[ak].css("height","auto");N[ak].css("width",ai.width);N[ak].css("max-width",ai["max-width"]);N[ak].css("min-width",ai["min-width"])};var ae=function(ai){N[ai].plain.outerHeight(N[ai].main.outerHeight())};var O=function(ai){f(j,N[ai]).each(function(){var al=f(this).attr("data-line");var ak=f("#"+al);var aj=null;if(N[ai].wrapped){ak.css("height","");aj=ak.outerHeight();aj=aj?aj:""}else{aj=ak.attr("data-height");aj=aj?aj:"";ak.css("height",aj)}f(this).css("height",aj)})};var ah=function(ai,aj){if(ai=="fast"){ai=200}else{if(ai=="slow"){ai=600}else{if(!S(ai)){ai=parseInt(ai);if(isNaN(ai)){return 0}}}}return ai*N[aj].time};var S=function(ai){return typeof ai=="number"}};f(document).ready(function(){CrayonSyntax.init()})})(jQueryCrayon);(function(b){var a=CrayonTagEditorSettings;window.CrayonQuickTags=new function(){var c=this;c.init=function(){c.sel='*[id*="crayon_quicktag"],*[class*="crayon_quicktag"]';var e=a.quicktag_text;e=e!==undefined?e:"crayon";QTags.addButton("crayon_quicktag",e,function(){CrayonTagEditor.showDialog({insert:function(g){QTags.insertContent(g)},select:c.getSelectedText,editor_str:"html",output:"encode"});b(c.sel).removeClass("qt_crayon_highlight")});var d;var f=setInterval(function(){d=b(c.sel).first();if(typeof d!="undefined"){CrayonTagEditor.bind(c.sel);clearInterval(f)}},100)};c.getSelectedText=function(){if(QTags.instances.length==0){return null}else{var f=QTags.instances[0];var e=f.canvas.selectionStart;var d=f.canvas.selectionEnd;return f.canvas.value.substring(e,d)}}};b(document).ready(function(){CrayonQuickTags.init()})})(jQueryCrayon); +/*! + Colorbox v1.5.9 - 2014-04-25 + jQuery lightbox and modal window plugin + (c) 2014 Jack Moore - http://www.jacklmoore.com/colorbox + license: http://www.opensource.org/licenses/mit-license.php + */ +(function(aT,a8,a4){function aZ(a,d,c){var b=a8.createElement(a);return d&&(b.id=ab+d),c&&(b.style.cssText=c),aT(b)}function aY(){return a4.innerHeight?a4.innerHeight:aT(a4).height()}function aV(b,a){a!==Object(a)&&(a={}),this.cache={},this.el=b,this.value=function(c){var d;return void 0===this.cache[c]&&(d=aT(this.el).attr("data-cbox-"+c),void 0!==d?this.cache[c]=d:void 0!==a[c]?this.cache[c]=a[c]:void 0!==ad[c]&&(this.cache[c]=ad[c])),this.cache[c]},this.get=function(d){var c=this.value(d);return aT.isFunction(c)?c.call(this.el,this):c}}function a5(b){var c=ag.length,a=(aM+b)%c;return 0>a?c+a:a}function bd(a,b){return Math.round((/%/.test(a)?("x"===b?az.width():aY())/100:1)*parseInt(a,10))}function aU(a,b){return a.get("photo")||a.get("photoRegex").test(b)}function a1(a,b){return a.get("retinaUrl")&&a4.devicePixelRatio>1?b.replace(a.get("photoRegex"),a.get("retinaSuffix")):b}function a9(a){"contains" in aP[0]&&!aP[0].contains(a.target)&&a.target!==aR[0]&&(a.stopPropagation(),aP.focus())}function ba(a){ba.str!==a&&(aP.add(aR).removeClass(ba.str).addClass(a),ba.str=a)}function a6(a){aM=0,a&&a!==!1?(ag=aT("."+af).filter(function(){var b=aT.data(this,ac),c=new aV(this,b);return c.get("rel")===a}),aM=ag.index(bf.el),-1===aM&&(ag=ag.add(bf.el),aM=ag.length-1)):ag=aT(bf.el)}function aS(a){aT(a8).trigger(a),aA.triggerHandler(a)}function a7(b){var g;if(!ax){if(g=aT(b).data("colorbox"),bf=new aV(b,g),a6(bf.get("rel")),!aH){aH=aW=!0,ba(bf.get("className")),aP.css({visibility:"hidden",display:"block",opacity:""}),ar=aZ(aG,"LoadedContent","width:0; height:0; overflow:hidden; visibility:hidden"),bb.css({width:"",height:""}).append(ar),aB=aj.height()+a2.height()+bb.outerHeight(!0)-bb.height(),a3=aC.width()+aw.width()+bb.outerWidth(!0)-bb.width(),aF=ar.outerHeight(!0),ap=ar.outerWidth(!0);var d=bd(bf.get("initialWidth"),"x"),c=bd(bf.get("initialHeight"),"y"),a=bf.get("maxWidth"),e=bf.get("maxHeight");bf.w=(a!==!1?Math.min(d,bd(a,"x")):d)-ap-a3,bf.h=(e!==!1?Math.min(c,bd(e,"y")):c)-aF-aB,ar.css({width:"",height:bf.h}),au.position(),aS(bc),bf.get("onOpen"),ao.add(av).hide(),aP.focus(),bf.get("trapFocus")&&a8.addEventListener&&(a8.addEventListener("focus",a9,!0),aA.one(aO,function(){a8.removeEventListener("focus",a9,!0)})),bf.get("returnFocus")&&aA.one(aO,function(){aT(bf.el).focus()})}aR.css({opacity:parseFloat(bf.get("opacity"))||"",cursor:bf.get("overlayClose")?"pointer":"",visibility:"visible"}).show(),bf.get("closeButton")?aE.html(bf.get("close")).appendTo(bb):aE.appendTo("
"),aQ()}}function aX(){!aP&&a8.body&&(ah=!1,az=aT(a4),aP=aZ(aG).attr({id:ac,"class":aT.support.opacity===!1?ab+"IE":"",role:"dialog",tabindex:"-1"}).hide(),aR=aZ(aG,"Overlay").hide(),ak=aT([aZ(aG,"LoadingOverlay")[0],aZ(aG,"LoadingGraphic")[0]]),aN=aZ(aG,"Wrapper"),bb=aZ(aG,"Content").append(av=aZ(aG,"Title"),al=aZ(aG,"Current"),an=aT('