]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 322693: Create a mechanism to manage multiple custom skins.
authorwurblzap%gmail.com <>
Thu, 7 Sep 2006 03:45:29 +0000 (03:45 +0000)
committerwurblzap%gmail.com <>
Thu, 7 Sep 2006 03:45:29 +0000 (03:45 +0000)
Patch by Marc Schumann <wurblzap@gmail.com>;
r=myk,mkanat; a=myk

Bugzilla/Constants.pm
Bugzilla/DB/Schema.pm
Bugzilla/Install.pm
Bugzilla/Install/DB.pm
Bugzilla/Install/Filesystem.pm
Bugzilla/User/Setting.pm
Bugzilla/User/Setting/Skin.pm [new file with mode: 0755]
template/en/default/global/code-error.html.tmpl
template/en/default/global/header.html.tmpl
template/en/default/global/setting-descs.none.tmpl

index 2d6c2f561b02120c66d06502e52f0816770ad02b..a0e869c33524c0a4186bf9b49874d90cae216cc6 100644 (file)
@@ -368,6 +368,7 @@ sub bz_locations {
         'localconfig' => "$libpath/$localconfig",
         'datadir'     => "$libpath/$datadir",
         'attachdir'   => "$libpath/$datadir/attachments",
+        'skinsdir'    => "$libpath/skins/contrib",
         # $webdotdir must be in the webtree somewhere. Even if you use a 
         # local dot, we output images to there. Also, if $webdotdir is 
         # not relative to the bugzilla root directory, you'll need to 
index 0a5cf9420ceb552e2f75d9a0cfeb0e451c04e5e5..ea25a125a1865de35af757533727dab3583919b1 100644 (file)
@@ -1047,6 +1047,7 @@ use constant ABSTRACT_SCHEMA => {
             default_value => {TYPE => 'varchar(32)', NOTNULL => 1},
             is_enabled    => {TYPE => 'BOOLEAN', NOTNULL => 1,
                               DEFAULT => 'TRUE'},
+            subclass      => {TYPE => 'varchar(32)'},
         ],
     },
 
index b014d6f6e82e5b736d71115bc5e30597da993ed5..d8fc478941ee56ffdf511a9af57c3fb9e8466e44 100644 (file)
@@ -50,6 +50,8 @@ use constant SETTINGS => {
     # 2006-05-01 olav@bkor.dhs.org -- Bug 7710
     state_addselfcc    => { options => ['always', 'never',  'cc_unless_role'],
                             default => 'cc_unless_role' },
+    # 2006-08-04 wurblzap@gmail.com -- Bug 322693
+    skin               => { subclass => 'Skin', default => 'standard' },
 
 };
 
@@ -75,8 +77,10 @@ use constant DEFAULT_COMPONENT => {
 sub update_settings {
     my %settings = %{SETTINGS()};
     foreach my $setting (keys %settings) {
-        add_setting($setting, $settings{$setting}->{options}, 
-                    $settings{$setting}->{default});
+        add_setting($setting,
+                    $settings{$setting}->{options}, 
+                    $settings{$setting}->{default},
+                    $settings{$setting}->{subclass});
     }
 }
 
index ccbb5f8cdc1bb9679b1421ff1296adc78fd4dc2d..d7918f6ac3be540b7e99ada57ecba9dc8528e540 100644 (file)
@@ -485,6 +485,8 @@ sub update_table_definitions {
 
     _update_longdescs_who_index();
 
+    $dbh->bz_add_column('setting', 'subclass', {TYPE => 'varchar(32)'});
+
     ################################################################
     # New --TABLE-- changes should go *** A B O V E *** this point #
     ################################################################
index 5261989dd2a8c1f6799a77463cb1eeb0098a9b13..43c964ba74c7f214cc60849540aa69ef25dffdb4 100644 (file)
@@ -184,6 +184,7 @@ sub FILESYSTEM {
         graphs                  => $ws_dir_writeable,
         $webdotdir              => $ws_dir_writeable,
         'skins/custom'          => $ws_dir_readable,
+        'skins/contrib'         => $ws_dir_readable,
     );
 
     # The name of each file, pointing at its default permissions and
index 71aeb2ef4cdaf202cdca5b40cd32e2af82e0ece6..7ed1b2f11cfa3ebeb4af3ad06b3ef0757e3dc09c 100644 (file)
@@ -14,6 +14,7 @@
 #
 # Contributor(s): Shane H. W. Travis <travis@sedsystems.ca>
 #                 Max Kanat-Alexander <mkanat@bugzilla.org>
+#                 Marc Schumann <wurblzap@gmail.com>
 #
 
 
@@ -39,10 +40,10 @@ sub new {
     my $user_id = shift;
 
     my $class = ref($invocant) || $invocant;
+    my $subclass = '';
 
     # Create a ref to an empty hash and bless it
     my $self = {};
-    bless($self, $class);
 
     my $dbh = Bugzilla->dbh;
 
@@ -60,9 +61,10 @@ sub new {
     # to retrieve the information for this setting ourselves.
     if (scalar @_ == 0) {
 
-        my ($default, $is_enabled, $value) = 
+        my ($default, $is_enabled, $value);
+        ($default, $is_enabled, $value, $subclass) = 
           $dbh->selectrow_array(
-             q{SELECT default_value, is_enabled, setting_value
+             q{SELECT default_value, is_enabled, setting_value, subclass
                  FROM setting
             LEFT JOIN profile_setting
                    ON setting.name = profile_setting.setting_name
@@ -73,9 +75,9 @@ sub new {
 
         # if not defined, then grab the default value
         if (! defined $value) {
-            ($default, $is_enabled) =
+            ($default, $is_enabled, $subclass) =
               $dbh->selectrow_array(
-                 q{SELECT default_value, is_enabled
+                 q{SELECT default_value, is_enabled, subclass
                    FROM setting
                    WHERE name = ?},
               undef,
@@ -96,12 +98,23 @@ sub new {
         }
     }
     else {
-      # If the values were passed in, simply assign them and return.
-      $self->{'is_enabled'}     = shift;
-      $self->{'default_value'}  = shift;
-      $self->{'value'}          = shift;
-      $self->{'is_default'}     = shift;
+        ($subclass) = $dbh->selectrow_array(
+            q{SELECT subclass FROM setting WHERE name = ?},
+            undef,
+            $setting_name);
+        # If the values were passed in, simply assign them and return.
+        $self->{'is_enabled'}    = shift;
+        $self->{'default_value'} = shift;
+        $self->{'value'}         = shift;
+        $self->{'is_default'}    = shift;
+    }
+    if ($subclass) {
+        eval('require ' . $class . '::' . $subclass);
+        $@ && ThrowCodeError('setting_subclass_invalid',
+                             {'subclass' => $subclass});
+        $class = $class . '::' . $subclass;
     }
+    bless($self, $class);
 
     $self->{'_setting_name'} = $setting_name;
     $self->{'_user_id'}      = $user_id;
@@ -114,18 +127,18 @@ sub new {
 ###############################
 
 sub add_setting {
-    my ($name, $values, $default_value) = @_;
+    my ($name, $values, $default_value, $subclass) = @_;
     my $dbh = Bugzilla->dbh;
 
     return if _setting_exists($name);
 
-    ($name && $values && $default_value)
+    ($name && $default_value)
       ||  ThrowCodeError("setting_info_invalid");
 
     print "Adding a new user setting called '$name'\n";
-    $dbh->do(q{INSERT INTO setting (name, default_value, is_enabled)
-                    VALUES (?, ?, 1)},
-             undef, ($name, $default_value));
+    $dbh->do(q{INSERT INTO setting (name, default_value, is_enabled, subclass)
+                    VALUES (?, ?, 1, ?)},
+             undef, ($name, $default_value, $subclass));
 
     my $sth = $dbh->prepare(q{INSERT INTO setting_value (name, value, sortindex)
                                     VALUES (?, ?, ?)});
diff --git a/Bugzilla/User/Setting/Skin.pm b/Bugzilla/User/Setting/Skin.pm
new file mode 100755 (executable)
index 0000000..c485850
--- /dev/null
@@ -0,0 +1,80 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Marc Schumann <wurblzap@gmail.com>
+#
+
+
+package Bugzilla::User::Setting::Skin;
+
+use strict;
+
+use base qw(Bugzilla::User::Setting);
+
+use Bugzilla::Constants;
+use File::Spec::Functions;
+use File::Basename;
+
+use constant BUILTIN_SKIN_NAMES => ['standard'];
+
+sub legal_values {
+    my ($self) = @_;
+
+    return $self->{'legal_values'} if defined $self->{'legal_values'};
+
+    my $dirbase = bz_locations()->{'skinsdir'};
+    # Avoid modification of the list BUILTIN_SKIN_NAMES points to by copying the
+    # list over instead of simply writing $legal_values = BUILTIN_SKIN_NAMES.
+    my @legal_values = @{(BUILTIN_SKIN_NAMES)};
+
+    foreach my $direntry (glob(catdir($dirbase, '*'))) {
+        if (-d $direntry) {
+            # Stylesheet set
+            push(@legal_values, basename($direntry));
+        }
+        elsif ($direntry =~ /\.css$/) {
+            # Single-file stylesheet
+            push(@legal_values, basename($direntry));
+        }
+    }
+
+    return $self->{'legal_values'} = \@legal_values;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::User::Setting::Skin - Object for a user preference setting for skins
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Skin.pm extends Bugzilla::User::Setting and implements a class specialized for
+skins settings.
+
+=head1 METHODS
+
+=over
+
+=item C<legal_values()>
+
+Description: Returns all legal skins
+Params:      none
+Returns:     A reference to an array containing the names of all legal skins
+
+=back
index a665243556aabd153a83bccbca909a073f281aa2..e62ef7abc631808dff6d930c5a2587b2ca8fcaff 100644 (file)
     option. Setting names must begin with a letter, and contain only
     letters, digits, or the symbols '_', '-', '.', or ':'.
 
+  [% ELSIF error == "setting_subclass_invalid" %]
+    There is no such Setting subclass as
+    <code>[% subclass FILTER html %]</code>.
+
   [% ELSIF error == "setting_value_invalid" %]
     The value "<code>[% value FILTER html %]</code>" is not in the list of
     legal values for the <em>[% name FILTER html %]</em> setting.
index e4a5f49543e0121a90d5749e5426cd3dce944ccb..0266984261e36624fa1876049b9148099d5df6a4 100644 (file)
@@ -46,6 +46,7 @@
   h2 = ""
   h3 = ""
   onload = ""
+  style_urls = []
 %]
 
 [%# We should be able to set the default value of the h1 variable
@@ -67,6 +68,8 @@
 
     [% PROCESS "global/site-navigation.html.tmpl" %]
 
+    [% PROCESS 'global/setting-descs.none.tmpl' %]
+
     [% IF javascript %]
       <script type="text/javascript">
         [% javascript %]
 
     [%+ INCLUDE "global/help-header.html.tmpl" %]
 
-    <link href="skins/standard/global.css" rel="stylesheet" type="text/css">
-    <link href="skins/custom/global.css" rel="stylesheet" type="text/css">
+    [%# Set up the skin CSS cascade:
+      #  1. Standard Bugzilla stylesheet set (persistent)
+      #  2. Standard Bugzilla stylesheet set (selectable)
+      #  3. All third-party "skin" stylesheet sets (selectable)
+      #  4. Page-specific styles
+      #  5. Custom Bugzilla stylesheet set (persistent)
+      # "Selectable" skin file sets may be either preferred or alternate.
+      # Exactly one is preferred, determined by the "skin" user preference.
+      #%]
+    [% IF user.settings.skin.value != 'standard' %]
+      [% user_skin = user.settings.skin.value %]
+    [% END %]
+    [% style_urls.unshift('skins/standard/global.css') %]
+
+    [%# CSS cascade, part 1: Standard Bugzilla stylesheet set (persistent).
+      # Always present.
+      #%]
+    [% FOREACH style_url = style_urls %]
+      <link href="[% style_url FILTER html %]"
+            rel="stylesheet"
+            type="text/css">
+    [% END %]
+
+    [%# CSS cascade, part 2: Standard Bugzilla stylesheet set (selectable)
+      # Present if skin selection is enabled.
+      #%]
+    [% IF user.settings.skin.is_enabled %]
+      [% FOREACH style_url = style_urls %]
+        <link href="[% style_url FILTER html %]"
+              rel="[% 'alternate ' IF user_skin %]stylesheet"
+              title="[% setting_descs.standard FILTER html %]"
+              type="text/css">
+      [% END %]
+    [% END %]
 
+    [%# CSS cascade, part 3: Third-party stylesheet set (selectable).
+      # All third-party skins are present if skin selection is enabled.
+      # The admin-selected skin is always present.
+      #%]
+    [% FOREACH contrib_skin = user.settings.skin.legal_values %]
+      [% NEXT IF contrib_skin == 'standard' %]
+      [% NEXT UNLESS contrib_skin == user_skin
+                  OR user.settings.skin.is_enabled %]
+      [% contrib_skin = contrib_skin FILTER url_quote %]
+      [% IF contrib_skin.match('\.css$') %]
+        [%# 1st skin variant: single-file stylesheet %]
+        <link href="[% "skins/contrib/$contrib_skin" %]"
+              rel="[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet"
+              title="[% contrib_skin FILTER html %]"
+              type="text/css">
+      [% ELSE %]
+        [%# 2nd skin variant: stylesheet set %]
+        [% FOREACH style_url = style_urls %]
+          [% IF style_url.match('^skins/standard/') %]
+            <link href="[% style_url.replace('^skins/standard/',
+                                             "skins/contrib/$contrib_skin/") %]"
+                  rel="[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet"
+                  title="[% contrib_skin FILTER html %]"
+                  type="text/css">
+          [% END %]
+        [% END %]
+      [% END %]
+    [% END %]
+
+    [%# CSS cascade, part 4: page-specific styles.
+      #%]
     [% IF style %]
       <style type="text/css">
         [% style %]
       </style>
     [% END %]
 
-    [% IF style_urls %]
-      [% FOREACH style_url = style_urls %]
-        <link href="[% style_url FILTER html %]" rel="stylesheet" type="text/css">
-        [% IF style_url.match('^skins/standard/') %]
-          <link href="[% style_url.replace('^skins/standard/', 'skins/custom/')
-                         FILTER html %]" rel="stylesheet" type="text/css">
-        [% END %]
+    [%# CSS cascade, part 5: Custom Bugzilla stylesheet set (persistent).
+      # Always present. Site administrators may override all other style
+      # definitions, including skins, using custom stylesheets.
+      #%]
+    [% FOREACH style_url = style_urls %]
+      [% IF style_url.match('^skins/standard/') %]
+        <link href="[% style_url.replace('^skins/standard/', "skins/custom/")
+                       FILTER html %]" rel="stylesheet" type="text/css">
       [% END %]
     [% END %]
 
index 6962d9ea697a75a86cb1c3ed9f6bb4b5d0f4b161..4fb2a031b51be8f164489f69011b999b2e47dd79 100644 (file)
@@ -33,6 +33,8 @@
    "post_bug_submit_action"           => "After changing $terms.abug",
    "next_bug"                         => "Show next $terms.bug in my list",
    "same_bug"                         => "Show the updated $terms.bug",
+   "standard"                         => "Classic",
+   "skin"                             => "$terms.Bugzilla's general appearance (skin)",
    "nothing"                          => "Do Nothing",
    "state_addselfcc"                  => "Automatically add me to the CC list of bugs I change",
    "always"                           => "Always",