Added color picker for WCF
authorAlexander Ebert <ebert@woltlab.com>
Mon, 8 Oct 2012 17:38:02 +0000 (19:38 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 8 Oct 2012 17:38:02 +0000 (19:38 +0200)
12 files changed:
com.woltlab.wcf/acpMenu.xml
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/images/colorPickerBar.png [new file with mode: 0644]
wcfsetup/install/files/images/colorPickerGradient.png [new file with mode: 0644]
wcfsetup/install/files/js/WCF.ColorPicker.js [new file with mode: 0644]
wcfsetup/install/files/lib/data/style/StyleAction.class.php
wcfsetup/install/files/lib/data/style/variable/StyleVariable.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/style/variable/StyleVariableAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/style/variable/StyleVariableEditor.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/style/variable/StyleVariableList.class.php [new file with mode: 0644]
wcfsetup/install/files/style/colorPicker.less [new file with mode: 0644]
wcfsetup/setup/db/install.sql

index 38b8142720cff6da9e1171ca68ef6c4f39373bb3..a571b014ec089c9f6535f756360a7542ef13c018 100644 (file)
                        <showorder>3</showorder>
                </acpmenuitem>
                
-               <!-- style -->
-               <acpmenuitem name="wcf.acp.menu.link.style">
-                       <parent>wcf.acp.menu.link.display</parent>
-                       <showorder>1</showorder>
-               </acpmenuitem>
-               
-               <acpmenuitem name="wcf.acp.menu.link.style.list">
-                       <link>index.php/StyleList/</link>
-                       <parent>wcf.acp.menu.link.style</parent>
-                       <permissions>admin.style.canEditStyle,admin.style.canDeleteStyle</permissions>
-                       <showorder>1</showorder>
-               </acpmenuitem>
-               
-               <acpmenuitem name="wcf.acp.menu.link.style.add">
-                       <link>index.php/StyleAdd/</link>
-                       <parent>wcf.acp.menu.link.style</parent>
-                       <permissions>admin.style.canAddStyle</permissions>
-                       <showorder>2</showorder>
-               </acpmenuitem>
-               <!-- /style -->
-               
                <acpmenuitem name="wcf.acp.menu.link.content">
                        <showorder>4</showorder>
                </acpmenuitem>
index 6c6e3dfcef4c96ccf4df915406966fea293592e1..957b989aa27a80250a29a91bc4e8f8c3d97e31d8 100644 (file)
@@ -44,9 +44,6 @@
                        <category name="admin.content">
                                <parent>admin</parent>
                        </category>
-                       <category name="admin.style">
-                               <parent>admin.display</parent>
-                       </category>
                        <category name="admin.language">
                                <parent>admin.display</parent>
                        </category>
                                <admindefaultvalue>1</admindefaultvalue>
                        </option>
                        
-                       <!-- admin.style -->
-                       <option name="admin.style.canAddStyle">
-                               <categoryname>admin.style</categoryname>
-                               <optiontype>boolean</optiontype>
-                               <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
-                       </option>
-                       <option name="admin.style.canEditStyle">
-                               <categoryname>admin.style</categoryname>
-                               <optiontype>boolean</optiontype>
-                               <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
-                       </option>
-                       <option name="admin.style.canDeleteStyle">
-                               <categoryname>admin.style</categoryname>
-                               <optiontype>boolean</optiontype>
-                               <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
-                       </option>
-                       <option name="admin.style.canUseDisabledStyle">
-                               <categoryname>admin.style</categoryname>
-                               <optiontype>boolean</optiontype>
-                               <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
-                       </option>
-                       <!-- /admin.style -->
-                       
                        <option name="admin.language.canAddLanguage">
                                <categoryname>admin.language</categoryname>
                                <optiontype>boolean</optiontype>
diff --git a/wcfsetup/install/files/images/colorPickerBar.png b/wcfsetup/install/files/images/colorPickerBar.png
new file mode 100644 (file)
index 0000000..65d4bec
Binary files /dev/null and b/wcfsetup/install/files/images/colorPickerBar.png differ
diff --git a/wcfsetup/install/files/images/colorPickerGradient.png b/wcfsetup/install/files/images/colorPickerGradient.png
new file mode 100644 (file)
index 0000000..608c3f7
Binary files /dev/null and b/wcfsetup/install/files/images/colorPickerGradient.png differ
diff --git a/wcfsetup/install/files/js/WCF.ColorPicker.js b/wcfsetup/install/files/js/WCF.ColorPicker.js
new file mode 100644 (file)
index 0000000..68c4f97
--- /dev/null
@@ -0,0 +1,628 @@
+WCF.ColorPicker = Class.extend({
+       /**
+        * hue bar element
+        * @var jQuery
+        */
+       _bar: null,
+       
+       /**
+        * bar selector is being moved
+        * @var boolean
+        */
+       _barActive: false,
+       
+       /**
+        * bar selector element
+        * @var jQuery
+        */
+       _barSelector: null,
+       
+       /**
+        * dialog overlay
+        * @var jQuery
+        */
+       _dialog: null,
+       
+       /**
+        * initialization state
+        * @var boolean
+        */
+       _didInit: false,
+       
+       /**
+        * active element id
+        * @var string
+        */
+       _elementID: '',
+       
+       /**
+        * saturation and value gradient element
+        * @var jQuery
+        */
+       _gradient: null,
+       
+       /**
+        * gradient selector is being moved
+        * @var boolean
+        */
+       _gradientActive: false,
+       
+       /**
+        * gradient selector element
+        * @var jQuery
+        */
+       _gradientSelector: null,
+       
+       /**
+        * HEX input element
+        * @var jQuery
+        */
+       _hex: null,
+       
+       /**
+        * HSV representation
+        * @var object
+        */
+       _hsv: { },
+       
+       /**
+        * visual new color element
+        * @var jQuery
+        */
+       _newColor: null,
+       
+       /**
+        * visual previous color element
+        * @var jQuery
+        */
+       _oldColor: null,
+       
+       /**
+        * list of RGBa input elements
+        * @var object
+        */
+       _rgba: { },
+       
+       /**
+        * RegExp to parse rgba()
+        * @var RegExp
+        */
+       _rgbaRegExp: null,
+       
+       /**
+        * Initializes the WCF.ColorPicker class.
+        * 
+        * @param       string          selector
+        */
+       init: function(selector) {
+               this._elementID = '';
+               this._hsv = { h: 0, s: 100, v: 100 };
+               this._position = { };
+               
+               var $elements = $(selector);
+               if (!$elements.length) {
+                       console.debug("[WCF.ColorPicker] Selector does not match any element, aborting.");
+                       return;
+               }
+               
+               $elements.click($.proxy(this._open, this));
+       },
+       
+       /**
+        * Opens the color picker overlay.
+        * 
+        * @param       object          event
+        */
+       _open: function(event) {
+               if (!this._didInit) {
+                       // init color picker on first usage
+                       this._initColorPicker();
+                       this._didInit = true;
+               }
+               
+               // load values from element
+               var $element = $(event.currentTarget);
+               this._elementID = $element.wcfIdentify();
+               this._parseColor($element);
+               
+               // set 'current' color
+               var $rgb = this.hsvToRgb(this._hsv.h, this._hsv.s, this._hsv.v);
+               this._oldColor.css({ backgroundColor: 'rgb(' + $rgb.r + ', ' + $rgb.g + ', ' + $rgb.b + ')' });
+               
+               this._dialog.wcfDialog({
+                       'title': WCF.Language.get('wcf.style.colorPicker')
+               });
+       },
+       
+       /**
+        * Parses the color of an element.
+        * 
+        * @param       jQuery          element
+        */
+       _parseColor: function(element) {
+               if (element.data('hsv')) {
+                       // create an explicit copy here, otherwise it would be only a reference
+                       var $hsv = element.data('hsv');
+                       for (var $type in $hsv) {
+                               this._hsv[$type] = $hsv[$type];
+                       }
+                       this._updateValues(null, true, true);
+                       this._rgba.a.val(parseInt(element.data('alpha')));
+               }
+               else {
+                       if (this._rgbaRegExp === null) {
+                               this._rgbaRegExp = new RegExp("^rgba\\((\\d{1,3}), ?(\\d{1,3}), ?(\\d{1,3}), ?(1|1\\.00?|0|0?\\.[0-9]{1,2})\\)$");
+                       }
+                       
+                       // parse value
+                       this._rgbaRegExp.exec(element.data('color'));
+                       var $alpha = RegExp.$4;
+                       // convert into x.yz
+                       if ($alpha.indexOf('.') === 0) {
+                               $alpha = "0" + $alpha;
+                       }
+                       $alpha *= 100;
+                       
+                       this._updateValues({
+                               r: RegExp.$1,
+                               g: RegExp.$2,
+                               b: RegExp.$3,
+                               a: Math.round($alpha)
+                       }, true, true);
+               }
+       },
+       
+       /**
+        * Initializes the color picker upon first usage.
+        */
+       _initColorPicker: function() {
+               this._dialog = $('<div id="colorPickerContainer" />').hide().appendTo(document.body);
+               
+               // create gradient
+               this._gradient = $('<div id="colorPickerGradient" />').appendTo(this._dialog);
+               this._gradientSelector = $('<span id="colorPickerGradientSelector"><span></span></span>').appendTo(this._gradient);
+               
+               // create bar
+               this._bar = $('<div id="colorPickerBar" />').appendTo(this._dialog);
+               this._barSelector = $('<span id="colorPickerBarSelector" />').appendTo(this._bar);
+               
+               // bind event listener
+               this._gradient.mousedown($.proxy(this._mouseDownGradient, this));
+               this._bar.mousedown($.proxy(this._mouseDownBar, this));
+               
+               var self = this;
+               $(document).mouseup(function(event) {
+                       if (self._barActive) {
+                               self._barActive = false;
+                               self._mouseBar(event);
+                       }
+                       else if (self._gradientActive) {
+                               self._gradientActive = false;
+                               self._mouseGradient(event);
+                       }
+               }).mousemove(function(event) {
+                       if (self._barActive) {
+                               self._mouseBar(event);
+                       }
+                       else if (self._gradientActive) {
+                               self._mouseGradient(event);
+                       }
+               });
+               
+               this._initColorPickerForm();
+       },
+       
+       /**
+        * Initializes the color picker input elements upon first usage.
+        */
+       _initColorPickerForm: function() {
+               var $form = $('<div id="colorPickerForm" />').appendTo(this._dialog);
+               
+               // new and current color
+               $('<small>' + WCF.Language.get('wcf.style.colorPicker.new') + '</small>').appendTo($form);
+               var $colors = $('<ul class="colors" />').appendTo($form);
+               this._newColor = $('<li class="new" />').appendTo($colors);
+               this._oldColor = $('<li class="old" />').appendTo($colors);
+               $('<small>' + WCF.Language.get('wcf.style.colorPicker.current') + '</small>').appendTo($form);
+               
+               // RGBa input
+               var $rgba = $('<ul class="rgba" />').appendTo($form);
+               this._createInputElement('r', 'R', 0, 255).appendTo($rgba);
+               this._createInputElement('g', 'G', 0, 255).appendTo($rgba);
+               this._createInputElement('b', 'B', 0, 255).appendTo($rgba);
+               this._createInputElement('a', 'a', 0, 100).appendTo($rgba);
+               
+               // HEX input
+               var $hex = $('<ul class="hex"><li><label><span>#</span></label></li></ul>').appendTo($form);
+               this._hex = $('<input type="text" maxlength="6" />').appendTo($hex.find('label'));
+               
+               // bind event listener
+               this._rgba.r.blur($.proxy(this._blurRgba, this));
+               this._rgba.g.blur($.proxy(this._blurRgba, this));
+               this._rgba.b.blur($.proxy(this._blurRgba, this));
+               this._rgba.a.blur($.proxy(this._blurRgba, this));
+               this._hex.blur($.proxy(this._blurHex, this));
+               
+               // submit button
+               var $submitForm = $('<div class="formSubmit" />').appendTo(this._dialog);
+               $('<button>' + WCF.Language.get('wcf.global.button.submit') + '</button>').appendTo($submitForm).click($.proxy(this._submit, this));
+       },
+       
+       /**
+        * Assigns the new color for active element.
+        */
+       _submit: function() {
+               var $rgb = this.hsvToRgb(this._hsv.h, this._hsv.s, this._hsv.v);
+               
+               // create an explicit copy here, otherwise it would be only a reference
+               var $hsv = { };
+               for (var $type in this._hsv) {
+                       $hsv[$type] = this._hsv[$type];
+               }
+               
+               var $element = $('#' + this._elementID);
+               $element.data('hsv', $hsv).css({ backgroundColor: 'rgb(' + $rgb.r + ', ' + $rgb.g + ', ' + $rgb.b + ')' }).data('alpha', parseInt(this._rgba.a.val()));
+               $('#' + $element.data('store')).val('rgba(' + this._rgba.r.val() + ', ' + this._rgba.g.val() + ', ' + this._rgba.b.val() + ', ' + (this._rgba.a.val() / 100) + ')');
+               
+               this._dialog.wcfDialog('close');
+       },
+       
+       /**
+        * Creates an input element.
+        * 
+        * @param       string          type
+        * @param       string          label
+        * @param       integer         min
+        * @param       integer         max
+        * @return      jQuery
+        */
+       _createInputElement: function(type, label, min, max) {
+               // create elements
+               var $listItem = $('<li class="' + type + '" />');
+               var $label = $('<label />').appendTo($listItem);
+               $('<span>' + label + '</span>').appendTo($label);
+               this._rgba[type] = $('<input type="number" value="0" min="' + min + '" max="' + max + '" step="1" />').appendTo($label);
+               
+               return $listItem;
+       },
+       
+       /**
+        * Handles the mouse down event on the gradient.
+        * 
+        * @param       object          event
+        */
+       _mouseDownGradient: function(event) {
+               this._gradientActive = true;
+               this._mouseGradient(event);
+       },
+       
+       /**
+        * Handles updates of gradient selector position.
+        * 
+        * @param       object          event
+        */
+       _mouseGradient: function(event) {
+               var $position = this._gradient.getOffsets('offset');
+               
+               var $left = Math.max(Math.min(event.pageX - $position.left, 255), 0);
+               var $top = Math.max(Math.min(event.pageY - $position.top, 255), 0);
+               
+               // calculate saturation and value
+               this._hsv.s = Math.max(0, Math.min(1, $left / 255)) * 100;
+               this._hsv.v = Math.max(0, Math.min(1, (255 - $top) / 255)) * 100;
+               
+               // update color
+               this._updateValues(null);
+       },
+       
+       /**
+        * Handles the mouse down event on the bar.
+        * 
+        * @param       object          event
+        */
+       _mouseDownBar: function(event) {
+               this._barActive = true;
+               this._mouseBar(event);
+       },
+       
+       /**
+        * Handles updates of the bar selector position.
+        * 
+        * @param       object          event
+        */
+       _mouseBar: function(event) {
+               var $position = this._bar.getOffsets('offset');
+               var $top = Math.max(Math.min(event.pageY - $position.top, 255), 0);
+               this._barSelector.css({ top: $top + 'px' });
+               
+               // calculate hue
+               this._hsv.h = Math.max(0, Math.min(359, Math.round((255 - $top) / 255 * 360)));
+               
+               // update color
+               this._updateValues(null);
+       },
+       
+       /**
+        * Handles changes of RGBa input fields.
+        */
+       _blurRgba: function() {
+               for (var $type in this._rgba) {
+                       var $value = parseInt(this._rgba[$type].val()) || 0;
+                       
+                       // alpha
+                       if ($type === 'a') {
+                               this._rgba[$type].val(Math.max(0, Math.min(100, $value)));
+                       }
+                       else {
+                               // rgb
+                               this._rgba[$type].val(Math.max(0, Math.min(255, $value)));
+                       }
+               }
+               
+               this._updateValues({
+                       r: this._rgba.r.val(),
+                       g: this._rgba.g.val(),
+                       b: this._rgba.b.val()
+               }, true, true);
+       },
+       
+       /**
+        * Handles change of HEX value.
+        */
+       _blurHex: function() {
+               var $value = this.hexToRgb(this._hex.val());
+               if ($value !== Number.NaN) {
+                       this._updateValues($value, true, true);
+               }
+       },
+       
+       /**
+        * Updates the values of all elements, including color picker and
+        * input elements. Argument 'rgb' may be null.
+        * 
+        * @param       object          rgb
+        * @param       boolean         changeH
+        * @param       boolean         changeSV
+        */
+       _updateValues: function(rgb, changeH, changeSV) {
+               changeH = (changeH === true) ? true : false;
+               changeSV = (changeSV === true) ? true : false;
+               
+               // calculate RGB values from HSV
+               if (rgb === null) {
+                       rgb = this.hsvToRgb(this._hsv.h, this._hsv.s, this._hsv.v);
+               }
+               
+               // add alpha channel
+               if (rgb.a === undefined) {
+                       rgb.a = this._rgba.a.val();
+               }
+               
+               // adjust RGBa input
+               for (var $type in rgb) {
+                       this._rgba[$type].val(rgb[$type]);
+               }
+               
+               // set hex input
+               this._hex.val(this.rgbToHex(rgb.r, rgb.g, rgb.b));
+               
+               // calculate HSV to adjust selectors
+               if (changeH || changeSV) {
+                       var $hsv = this.rgbToHsv(rgb.r, rgb.g, rgb.b);
+                       
+                       // adjust hue
+                       if (changeH) {
+                               this._hsv.h = $hsv.h;
+                       }
+                       
+                       // adjust saturation and value
+                       if (changeSV) {
+                               this._hsv.s = $hsv.s;
+                               this._hsv.v = $hsv.v;
+                       }
+               }
+               
+               // adjust bar selector
+               var $top = Math.max(0, Math.min(255, 255 - (this._hsv.h / 360) * 255));
+               this._barSelector.css({ top: $top + 'px' });
+               
+               // adjust gradient selector
+               var $left = Math.max(0, Math.min(255, (this._hsv.s / 100) * 255));
+               var $top = Math.max(0, Math.min(255, 255 - ((this._hsv.v / 100) * 255)));
+               this._gradientSelector.css({
+                       left: ($left - 6) + 'px',
+                       top: ($top - 6) + 'px'
+               });
+                               
+               // update 'new' color
+               this._newColor.css({ backgroundColor: 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')' });
+               
+               // adjust gradient color
+               var $rgb = this.hsvToRgb(this._hsv.h, 100, 100);
+               this._gradient.css({ backgroundColor: 'rgb(' + $rgb.r + ', ' + $rgb.g + ', ' + $rgb.b + ')' });
+       },
+       
+       /**
+        * Converts a HSV color into RGB.
+        * 
+        * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+        * 
+        * @param       integer         h
+        * @param       integer         s
+        * @param       integer         v
+        * @return      object
+        */
+       hsvToRgb: function(h, s, v) {
+               var $rgb = { r: 0, g: 0, b: 0 };
+               var $h, $f, $p, $q, $t;
+               
+               $h = Math.floor(h / 60);
+               $f = h / 60 - $h;
+               
+               s /= 100;
+               v /= 100;
+               
+               $p = v * (1 - s);
+               $q = v * (1 - s * $f);
+               $t = v * (1 - s * (1 - $f));
+               
+               if (s == 0) {
+                       $rgb.r = $rgb.g = $rgb.b = v;
+               }
+               else {
+                       switch ($h) {
+                               case 1:
+                                       $rgb.r = $q;
+                                       $rgb.g = v;
+                                       $rgb.b = $p;
+                               break;
+                               
+                               case 2:
+                                       $rgb.r = $p;
+                                       $rgb.g = v;
+                                       $rgb.b = $t;
+                               break;
+                               
+                               case 3:
+                                       $rgb.r = $p;
+                                       $rgb.g = $q;
+                                       $rgb.b = v;
+                               break;
+                               
+                               case 4:
+                                       $rgb.r = $t;
+                                       $rgb.g = $p;
+                                       $rgb.b = v;
+                               break;
+                               
+                               case 5:
+                                       $rgb.r = v;
+                                       $rgb.g = $p;
+                                       $rgb.b = $q;
+                               break;
+                               
+                               case 0:
+                               case 6:
+                                       $rgb.r = v;
+                                       $rgb.g = $t;
+                                       $rgb.b = $p;
+                               break;
+                       }
+               }
+               
+               return {
+                       r: Math.round($rgb.r * 255),
+                       g: Math.round($rgb.g * 255),
+                       b: Math.round($rgb.b * 255)
+               };
+       },
+       
+       /**
+        * Converts a RGB color into HSV.
+        * 
+        * @see https://secure.wikimedia.org/wikipedia/de/wiki/HSV-Farbraum#Transformation_von_RGB_und_HSV
+        * 
+        * @param       integer         r
+        * @param       integer         g
+        * @param       integer         b
+        * @return      object
+        */
+       rgbToHsv: function(r, g, b) {
+               var $h, $s, $v;
+               var $max, $min, $diff;
+               
+               r /= 255;
+               g /= 255;
+               b /= 255;
+               
+               $max = Math.max(Math.max(r, g), b);
+               $min = Math.min(Math.min(r, g), b);
+               $diff = $max - $min;
+               
+               $h = 0;
+               if ($max !== $min) {
+                       switch ($max) {
+                               case r:
+                                       $h = 60 * (0 + (g - b) / $diff);
+                               break;
+                               
+                               case g:
+                                       $h = 60 * (2 + (b - r) / $diff);
+                               break;
+                               
+                               case b:
+                                       $h = 60 * (4 + (r - g) / $diff);
+                               break;
+                       }
+                       
+                       if ($h < 0) {
+                               $h += 360;
+                       }
+               }
+               
+               if ($max === 0) {
+                       $s = 0;
+               }
+               else {
+                       $s = $diff / $max;
+               }
+               
+               $v = $max;
+               
+               return {
+                       h: Math.round($h),
+                       s: Math.round($s * 100),
+                       v: Math.round($v * 100)
+               };
+       },
+       
+       /**
+        * Converts HEX into RGB.
+        * 
+        * @param       string          hex
+        * @return      object
+        */
+       hexToRgb: function(hex) {
+               if (/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)) {
+                       // only convert #abc and #abcdef
+                       hex = hex.split('');
+                       
+                       // drop the hashtag
+                       if (hex[0] === '#') {
+                               hex.shift();
+                       }
+                       
+                       // parse shorthand #xyz
+                       if (hex.length === 3) {
+                               return {
+                                       r: parseInt(hex[0] + '' + hex[0], 16),
+                                       g: parseInt(hex[1] + '' + hex[1], 16),
+                                       b: parseInt(hex[2] + '' + hex[2], 16)
+                               };
+                       }
+                       else {
+                               return {
+                                       r: parseInt(hex[0] + '' + hex[1], 16),
+                                       g: parseInt(hex[2] + '' + hex[3], 16),
+                                       b: parseInt(hex[4] + '' + hex[5], 16)
+                               };
+                       }
+               }
+               
+               return Number.NaN;
+       },
+       
+       /**
+        * Converts a RGB into HEX.
+        * 
+        * @see http://www.linuxtopia.org/online_books/javascript_guides/javascript_faq/rgbtohex.htm
+        * 
+        * @param       integer         r
+        * @param       integer         g
+        * @param       integer         b
+        * @return      string
+        */
+       rgbToHex: function(r, g, b) {
+               return ("0123456789ABCDEF".charAt((r - r % 16) / 16) + '' + "0123456789ABCDEF".charAt(r % 16)) + '' + ("0123456789ABCDEF".charAt((g - g % 16) / 16) + '' + "0123456789ABCDEF".charAt(g % 16)) + '' + ("0123456789ABCDEF".charAt((b - b % 16) / 16) + '' + "0123456789ABCDEF".charAt(b % 16));
+       }
+});
\ No newline at end of file
index 99baa14eb68fe2f62f2d8d9fa4a10ae23c9d26e7..218c98e9f7d91f58f8bedad018b9da3076479593 100644 (file)
@@ -1,12 +1,13 @@
 <?php
 namespace wcf\data\style;
 use wcf\data\AbstractDatabaseObjectAction;
+use wcf\system\WCF;
 
 /**
  * Executes style-related actions.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2010 WoltLab GmbH
+ * @copyright  2001-2012 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    com.woltlab.wcf
  * @subpackage data.style
@@ -17,4 +18,53 @@ class StyleAction extends AbstractDatabaseObjectAction {
         * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
        protected $className = 'wcf\data\style\StyleEditor';
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::create()
+        */
+       public function create() {
+               $style = parent::create();
+               
+               // add variables
+               if (isset($this->parameters['variables']) && !empty($this->parameters['variables'])) {
+                       $sql = "SELECT  variableID, variableName, defaultValue
+                               FROM    wcf".WCF_N."_style_variable";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute();
+                       $variables = array();
+                       while ($row = $statement->fetchArray()) {
+                               $variableName = $row['variableName'];
+                               
+                               // ignore variables with identical value
+                               if (isset($this->parameters['variables'][$variableName])) {
+                                       if ($this->parameters['variables'][$variableName] == $row['defaultValue']) {
+                                               continue;
+                                       }
+                                       else {
+                                               $variables[$row['variableID']] = $this->parameters['variables'][$variableName];
+                                       }
+                               }
+                       }
+                       
+                       // insert variables that differ from default values
+                       if (!empty($variables)) {
+                               $sql = "INSERT INTO     wcf".WCF_N."_style_variable_value
+                                                       (styleID, variableID, variableValue)
+                                       VALUES          (?, ?, ?)";
+                               $statement = WCF::getDB()->prepareStatement($sql);
+                               
+                               WCF::getDB()->beginTransaction();
+                               foreach ($variables as $variableID => $variableValue) {
+                                       $statement->execute(array(
+                                               $style->styleID,
+                                               $variableID,
+                                               $variableValue
+                                       ));
+                               }
+                               WCF::getDB()->commitTransaction();
+                       }
+               }
+               
+               return $style;
+       }
 }
diff --git a/wcfsetup/install/files/lib/data/style/variable/StyleVariable.class.php b/wcfsetup/install/files/lib/data/style/variable/StyleVariable.class.php
new file mode 100644 (file)
index 0000000..d12505b
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+namespace wcf\data\style\variable;
+use wcf\data\DatabaseObject;
+
+/**
+ * Represents a style variable.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.style.variable
+ * @category   Community Framework
+ */
+class StyleVariable extends DatabaseObject {
+       /**
+        * @see wcf\data\DatabaseObject::$databaseTableName
+        */
+       protected static $databaseTableName = 'style_variable';
+       
+       /**
+        * @see wcf\data\DatabaseObject::$databaseTableIndexName
+        */
+       protected static $databaseTableIndexName = 'variableID';
+       
+       const TYPE_COLOR = 'color';
+       const TYPE_TEXT = 'text';
+       const TYPE_UNIT = 'unit';
+}
diff --git a/wcfsetup/install/files/lib/data/style/variable/StyleVariableAction.class.php b/wcfsetup/install/files/lib/data/style/variable/StyleVariableAction.class.php
new file mode 100644 (file)
index 0000000..2d077e4
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+namespace wcf\data\style\variable;
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes style variable-related actions.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.style.variable
+ * @category   Community Framework
+ */
+class StyleVariableAction extends AbstractDatabaseObjectAction {
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::$className
+        */
+       protected $className = 'wcf\data\style\variable\StyleVariableEditor';
+}
diff --git a/wcfsetup/install/files/lib/data/style/variable/StyleVariableEditor.class.php b/wcfsetup/install/files/lib/data/style/variable/StyleVariableEditor.class.php
new file mode 100644 (file)
index 0000000..1c41990
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+namespace wcf\data\style\variable;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to create, edit and delete a style variable.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.style.variable
+ * @category   Community Framework
+ */
+class StyleVariableEditor extends DatabaseObjectEditor {
+       /**
+        * @see wcf\data\DatabaseObjectDecorator::$baseClass
+        */
+       protected static $baseClass = 'wcf\data\style\variable\StyleVariable';
+}
diff --git a/wcfsetup/install/files/lib/data/style/variable/StyleVariableList.class.php b/wcfsetup/install/files/lib/data/style/variable/StyleVariableList.class.php
new file mode 100644 (file)
index 0000000..405727d
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+namespace wcf\data\style\variable;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of style variables.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.style.variable
+ * @category   Community Framework
+ */
+class StyleVariableList extends DatabaseObjectList {
+       /**
+        * @see wcf\data\DatabaseObjectList::$className
+        */
+       public $className = 'wcf\data\style\variable\StyleVariable';
+}
diff --git a/wcfsetup/install/files/style/colorPicker.less b/wcfsetup/install/files/style/colorPicker.less
new file mode 100644 (file)
index 0000000..58e0ae2
--- /dev/null
@@ -0,0 +1,121 @@
+#colorPickerGradient {
+       background-color: #f00;
+       background-image: url('images/colorPickerGradient.png');
+       background-repeat: no-repeat;
+       border: 1px solid rgba(0, 0, 0, 1);
+       cursor: default;
+       display: inline-block;
+       height: 256px;
+       overflow: hidden;
+       position: relative;
+       width: 256px;
+       
+       > span {
+               border: 1px solid rgba(0, 0, 0, 1);
+               border-radius: 10px;
+               display: block;
+               height: 10px;
+               left: -4px;
+               position: absolute;
+               top: -4px;
+               width: 10px;
+               
+               > span {
+                       border: 1px solid rgba(255, 255, 255, 1);
+                       border-radius: 10px;
+                       display: block;
+                       height: 8px;
+                       width: 8px;
+               }
+       }
+} 
+
+#colorPickerBar {
+       background-image: url('images/colorPickerBar.png');
+       background-repeat: repeat-x;
+       border: 1px solid rgba(0, 0, 0, 1);
+       cursor: default;
+       display: inline-block;
+       height: 256px;
+       margin-left: 10px;
+       position: relative;
+       width: 16px;
+       
+       > span {
+               display: inline-block;
+               height: 1px;
+               left: 0;
+               position: absolute;
+               top: 27px;
+               width: 16px;
+
+               &:after,
+               &:before {
+                       content: "";
+                       display: block;
+                       height: 0;
+                       position: absolute;
+                       top: 0;
+                       width: 0;
+               }
+               
+               &:after {
+                       border-bottom: 5px solid transparent;
+                       border-right: 5px solid rgba(0, 0, 0, 1);
+                       border-top: 5px solid transparent;
+                       right: -7px;
+                       top: -5px;
+               }
+               
+               &:before {
+                       border-bottom: 5px solid transparent;
+                       border-left: 5px solid rgba(0, 0, 0, 1);
+                       border-top: 5px solid transparent;
+                       left: -7px;
+                       top: -5px;
+               }
+       }
+}
+
+#colorPickerForm {
+       display: inline-block;
+       margin-left: 20px;
+       position: relative;
+       text-align: right;
+       width: 100px;
+
+       > .colors {
+               > .new,
+               > .old {
+                       border: 1px solid rgba(0, 0, 0, 1);
+                       display: block;
+                       height: 24px;
+               }
+               
+               > .old {
+                       border-top-width: 0;
+               }
+       }
+       
+       > .hex {
+               margin-top: 21px;
+       }
+       
+       > .rgba {
+               margin-top: 21px;
+               
+               > li.a {
+                       margin-top: 7px;
+               }
+       }
+       
+       > .rgba > li,
+       > .hex > li {
+               text-align: right;
+               
+               input {
+                       margin-left: 7px;
+                       width: 80px;
+               }
+       }
+}
index bdfccb5bfe6a7ff61aaaaf4829cd7ad557c22ddd..58a3be2dd3298d446803667bf3ee1c7f8e1f1f94 100644 (file)
@@ -575,6 +575,7 @@ CREATE TABLE wcf1_style (
        authorName VARCHAR(255) NOT NULL DEFAULT '',
        authorURL VARCHAR(255) NOT NULL DEFAULT '',
        iconPath VARCHAR(255) NOT NULL DEFAULT '',
+       imagePath VARCHAR(255) NOT NULL DEFAULT ''
 );
 
 DROP TABLE IF EXISTS wcf1_style_to_package;
@@ -1014,3 +1015,4 @@ INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('wcfMainMen
 INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('wcfMainMenuColor', 'rgba(102, 102, 102, 1)');
 INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('wcfMainMenuActiveColor', 'rgba(0, 0, 0, 1)');
 INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('wcfMarkedBackgroundColor', 'rgba(255, 255, 200, 1)');
+INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('useFluidLayout', '1');