diff --git a/modules/themeroller/controllers/admin_themeroller.php b/modules/themeroller/controllers/admin_themeroller.php
new file mode 100755
index 00000000..89a9a57e
--- /dev/null
+++ b/modules/themeroller/controllers/admin_themeroller.php
@@ -0,0 +1,180 @@
+form, $v->errors) = $this->_get_upload_form();
+ $v->is_writable = is_writable(THEMEPATH);
+ $v->action = "admin/themeroller/form_create";
+ $submit_class = "ui-state-default ui-corner-all submit g-left";
+
+ if ($v->not_writable = !is_writable(THEMEPATH)) {
+ $submit_class .= " ui-state-disabled";
+ }
+ $v->submit_class = $submit_class;
+ $v->script_data = array(
+ "g3sid" => Session::instance()->id(),
+ "user_agent" => Input::instance()->server("HTTP_USER_AGENT"),
+ "csrf" => access::csrf_token());
+ json::reply(array("html" => (string) $v));
+ }
+
+ public function form_create() {
+ $theme_name = Session::instance()->get_once("theme_name");
+ json::reply(array("html" => (string) $this->_get_theme_form($theme_name)));
+ }
+
+ public function upload() {
+ access::verify_csrf();
+
+ //list ($v->form, $v->errors) = $this->_get_upload_form();
+
+ $validation = new Validation(array_merge($_POST, $_FILES));
+ $validation->add_rules("zip_file", "upload::valid", "upload::required", "upload::type[zip]");
+ $validation->add_rules("is_admin", "chars[0,1]");
+ $validation->add_callbacks("zip_file", array($this, "_unload_zip"));
+ if ($validation->validate()) {
+ $session = Session::instance();
+ $themeroller_name = $session->get("themeroller_name");
+ $is_admin = $validation["is_admin"];
+ $counter = 0;
+ $theme_name_generated = ($is_admin ? "admin_" : "") . $themeroller_name;
+ while (file_exists(THEMEPATH . "$theme_name_generated/theme.info")) {
+ $counter++;
+ $theme_name_generated = "{$theme_name_generated}_{$counter}";
+ }
+
+ $theme_name = strtolower(strtr($theme_name_generated, " ", "_"));
+ $session->set("theme_name", $theme_name);
+ $session->set("themeroller_is_admin", $is_admin);
+ print "FILEID: {$validation["zip_file"]["tmp_name"]}";
+ } else {
+ header("HTTP/1.1 400 Bad Request");
+ print "ERROR: " . t("Invalid zip archive");
+ }
+ }
+
+ public function create() {
+ access::verify_csrf();
+
+ $form = $this->_get_theme_form();
+ if ($form->validate()) {
+ $session = Session::instance();
+ $extract_path = $session->get_once("theme_extract_path");
+ $v = new View("admin_themeroller_progress.html");
+
+ $task_def = Task_Definition::factory()
+ ->callback("themeroller_task::create_theme")
+ ->description(t("Generate theme from a themeroller archive"))
+ ->name(t("Generate theme"));
+
+ $v->task = task::create($task_def,
+ array("path" => $extract_path,
+ "original_name" => $form->theme->original->value,
+ "theme_name" => $form->theme->theme_name->value,
+ "display_name" => $form->theme->display_name->value,
+ "description" => $form->theme->description->value,
+ "is_admin" => $session->get("themeroller_is_admin")));
+
+ json::reply(array("html" => (string) $v));
+ } else {
+ json::reply(array("result" => "error", "html" => (string) $form));
+ }
+ }
+
+ /**
+ * Run the task of creating the theme
+ */
+ static function run($task_id) {
+ access::verify_csrf();
+
+ $task = ORM::factory("task", $task_id);
+ if (!$task->loaded() || $task->owner_id != identity::active_user()->id) {
+ access::forbidden();
+ }
+
+ $task = task::run($task_id);
+
+ // Prevent the JavaScript code from breaking by forcing a period as
+ // decimal separator for all locales with sprintf("%F", $value).
+ json::reply(array("done" => (bool)$task->done,
+ "status" => (string)$task->status,
+ "percent_complete" => sprintf("%F", $task->percent_complete)));
+ }
+
+ static function _is_theme_defined($name) {
+ $theme_name = strtolower(strtr($name->value, " ", "_"));
+ if (file_exists(THEMEPATH . "$theme_name/theme.info")) {
+ $name->add_error("conflict", 1);
+ }
+ }
+
+ public function _unload_zip(Validation $post, $field) {
+ $zipfile = $post["zip_file"]["tmp_name"];
+ if (false !== ($extract_path = themeroller::extract_zip_file($zipfile))) {
+ $theme_name = themeroller::get_theme_name($extract_path);
+ if (!empty($theme_name)) {
+ Session::instance()->set("themeroller_name", $theme_name);
+ } else {
+ Kohana_Log::add("error", "zip file: css directory not found");
+ $post->add_error($field, "invalid zipfile");
+ }
+ } else {
+ Kohana_Log::add("error", "zip file: open failed");
+ $post->add_error($field, "invalid zipfile");
+ }
+ if (file_exists($zipfile)) {
+ unlink($zipfile);
+ }
+ }
+
+ private function _get_theme_form($theme_name=null) {
+ $form = new Forge("admin/themeroller/create", "", "post", array("id" => "g-themeroller-create-form"));
+ $form_group = $form->group("theme")->label(t("Create theme"));
+ $original_name = $form_group->hidden("original");
+ $name_field = $form_group->input("theme_name")->label(t("Theme Name"))->id("g-name")
+ ->rules("required")
+ ->callback("Admin_Themeroller_Controller::_is_theme_defined")
+ ->error_messages("conflict", t("There is already a theme with that name"))
+ ->error_messages("required", t("You must enter a theme name"));
+ $display_name = $form_group->input("display_name")->label(t("Display Name"))
+ ->id("g-display-name")
+ ->rules("required")
+ ->error_messages("required", t("You must enter a theme display name"));
+ if (!empty($theme_name)) {
+ $name_field->value($theme_name);
+ $display_name->value(ucwords(t("%name theme", array("name" => $theme_name))));
+ $original_name->hidden("original")->value(Session::instance()->get("themeroller_name"));
+ }
+ $form_group->textarea("description")->label(t("Description"))
+ ->id("g-description")
+ ->rules("required")
+ ->error_messages("required", t("You must enter a theme description name"));
+ $form_group->submit("")->value(t("Create"));
+
+ return $form;
+ }
+
+ private function _get_upload_form() {
+ $form = array("zip_file" => "", "is_admin" => "");
+ $errors = array_fill_keys(array_keys($form), "");
+ return array($form, $errors);
+ }
+}
\ No newline at end of file
diff --git a/modules/themeroller/data/admin_views/admin.html.php b/modules/themeroller/data/admin_views/admin.html.php
new file mode 100644
index 00000000..f9ef18c7
--- /dev/null
+++ b/modules/themeroller/data/admin_views/admin.html.php
@@ -0,0 +1,87 @@
+
+
+
+
+
+ else: ?>
+
+ endif; ?>
+ = $theme->site_status() ?>
+
+
+
+
+
+ = $theme->messages() ?>
+ = $content ?>
+
+
+
+ if ($sidebar): ?>
+
+ endif ?>
+
+
+
+ = $theme->admin_page_bottom() ?>
+
+
diff --git a/modules/themeroller/data/admin_views/block.html.php b/modules/themeroller/data/admin_views/block.html.php
new file mode 100644
index 00000000..d1d2d088
--- /dev/null
+++ b/modules/themeroller/data/admin_views/block.html.php
@@ -0,0 +1,18 @@
+
+ if ($anchor): ?>
+
+ endif ?>
+
diff --git a/modules/themeroller/data/admin_views/pager.html.php b/modules/themeroller/data/admin_views/pager.html.php
new file mode 100644
index 00000000..5fff5845
--- /dev/null
+++ b/modules/themeroller/data/admin_views/pager.html.php
@@ -0,0 +1,44 @@
+
+ // See http://docs.kohanaphp.com/libraries/pagination ?>
+
diff --git a/modules/themeroller/data/css/fix-ie.css b/modules/themeroller/data/css/fix-ie.css
new file mode 100644
index 00000000..ac100da4
--- /dev/null
+++ b/modules/themeroller/data/css/fix-ie.css
@@ -0,0 +1,53 @@
+/**
+ * Fix display in IE 6, 7
+ */
+
+#g-banner {
+ z-index: 2;
+ zoom: 1;
+}
+
+#g-sidebar {
+ overflow: hidden;
+}
+
+#g-photo,
+#g-movie {
+ zoom: 1;
+}
+
+#g-photo .g-context-menu,
+#g-movie .g-context-menu {
+ width: 240px;
+}
+
+input.submit {
+ clear: none !important;
+ display: inline !important;
+}
+
+.g-short-form input[type='submit'] {
+ line-height: 1em;
+ padding: .38em .3em;
+}
+
+#g-add-tag-form input.textbox {
+ width: 110px !important;
+}
+
+#g-add-tag-form input[type='submit'] {
+ padding: .3em 0 !important;
+}
+
+#g-dialog .g-cancel {
+ display: inline-block !important;
+ float: none !important;
+}
+
+.g-paginator .g-text-right {
+ width: 29%;
+}
+
+.g-paginator .ui-icon-right {
+ width: 60px;
+}
diff --git a/modules/themeroller/data/js/admin_ui.init.js b/modules/themeroller/data/js/admin_ui.init.js
new file mode 100644
index 00000000..4ed912f8
--- /dev/null
+++ b/modules/themeroller/data/js/admin_ui.init.js
@@ -0,0 +1,62 @@
+/**
+ * Initialize jQuery UI and Gallery Plugins
+ * @todo Move ui-corner-all assignments to theme admin views
+ */
+
+$(document).ready(function(){
+
+ // Initialize Superfish menus
+ $("#g-site-admin-menu .g-menu").hide().addClass("sf-menu");
+ $("#g-site-admin-menu .g-menu").superfish({
+ delay: 500,
+ animation: {
+ opacity: "show",
+ height: "show"
+ },
+ pathClass: "g-selected",
+ speed: "fast"
+ }).show();
+
+ // Initialize status message effects
+ $("#g-action-status li").gallery_show_message();
+
+ // Initialize modal dialogs
+ $(".g-dialog-link").gallery_dialog();
+
+ // Initialize short forms
+ $(".g-short-form").gallery_short_form();
+
+ // Initialize ajax links
+ $(".g-ajax-link").gallery_ajax();
+
+ // Initialize panels
+ $(".g-panel-link").gallery_panel();
+
+ if ($("#g-photo-stream").length) {
+ // Vertically align thumbs in photostream
+ $(".g-item").gallery_valign();
+ }
+
+ // Apply jQuery UI button css to submit inputs
+ $("input[type=submit]:not(.g-short-form input)").addClass("ui-state-default ui-corner-all");
+
+ // Round view menu buttons
+ if ($("#g-admin-comments-menu").length) {
+ $("#g-admin-comments-menu ul").removeClass("g-menu");
+ $("#g-admin-comments-menu").addClass("g-buttonset");
+ $("#g-admin-comments-menu a").addClass("g-button ui-state-default");
+ $("#g-admin-comments-menu ul li:first a").addClass("ui-corner-left");
+ $("#g-admin-comments-menu ul li:last a").addClass("ui-corner-right");
+ }
+
+ // Round corners
+ $(".g-selected").addClass("ui-corner-all");
+ $(".g-available .g-block").addClass("ui-corner-all");
+ $(".g-unavailable").addClass("ui-corner-all");
+
+ // Remove titles for menu options since we're displaying that text anyway
+ $(".sf-menu a, .sf-menu li").removeAttr("title");
+
+ // Initialize button hover effect
+ $.fn.gallery_hover_init();
+});
diff --git a/modules/themeroller/data/js/site_ui.init.js b/modules/themeroller/data/js/site_ui.init.js
new file mode 100644
index 00000000..a4fc0e2f
--- /dev/null
+++ b/modules/themeroller/data/js/site_ui.init.js
@@ -0,0 +1,122 @@
+/**
+ * Initialize jQuery UI and Gallery Plugins
+ */
+
+$(document).ready(function() {
+
+ // Initialize Superfish menus (hidden, then shown to address IE issue)
+ $("#g-site-menu .g-menu").hide().addClass("sf-menu");
+ $("#g-site-menu .g-menu").superfish({
+ delay: 500,
+ animation: {
+ opacity:'show',
+ height:'show'
+ },
+ pathClass: "g-selected",
+ speed: 'fast'
+ }).show();
+
+ // Initialize status message effects
+ $("#g-action-status li").gallery_show_message();
+
+ // Initialize dialogs
+ $(".g-dialog-link").gallery_dialog();
+
+ // Initialize short forms
+ $(".g-short-form").gallery_short_form();
+
+ // Apply jQuery UI icon, hover, and rounded corner styles
+ $("input[type=submit]:not(.g-short-form input)").addClass("ui-state-default ui-corner-all");
+ if ($("#g-view-menu").length) {
+ $("#g-view-menu ul").removeClass("g-menu").removeClass("sf-menu");
+ $("#g-view-menu a").addClass("ui-icon");
+ }
+
+ // Apply jQuery UI icon and hover styles to context menus
+ if ($(".g-context-menu").length) {
+ $(".g-context-menu li").addClass("ui-state-default");
+ $(".g-context-menu a").addClass("g-button ui-icon-left");
+ $(".g-context-menu a").prepend("
");
+ $(".g-context-menu a span").each(function() {
+ var iconClass = $(this).parent().attr("class").match(/ui-icon-.[^\s]+/).toString();
+ $(this).addClass(iconClass);
+ });
+ }
+
+ // Remove titles for menu options since we're displaying that text anyway
+ $(".sf-menu a, .sf-menu li").removeAttr("title");
+
+ // Album and search results views
+ if ($("#g-album-grid").length) {
+ // Set equal height for album items and vertically align thumbnails/metadata
+ $('.g-item').equal_heights().gallery_valign();
+
+ // Initialize thumbnail hover effect
+ $(".g-item").hover(
+ function() {
+ // Insert a placeholder to hold the item's position in the grid
+ var placeHolder = $(this).clone().attr("id", "g-place-holder");
+ $(this).after($(placeHolder));
+ // Style and position the hover item
+ var position = $(this).position();
+ $(this).css("top", position.top).css("left", position.left);
+ $(this).addClass("g-hover-item");
+ // Initialize the contextual menu
+ $(this).gallery_context_menu();
+ // Set the hover item's height
+ $(this).height("auto");
+ var context_menu = $(this).find(".g-context-menu");
+ var adj_height = $(this).height() + context_menu.height();
+ if ($(this).next().height() > $(this).height()) {
+ $(this).height($(this).next().height());
+ } else if ($(this).prev().height() > $(this).height()) {
+ $(this).height($(this).prev().height());
+ } else {
+ $(this).height(adj_height);
+ }
+ },
+ function() {
+ // Reset item height and position
+ if ($(this).next().height()) {
+ var sib_height = $(this).next().height();
+ } else {
+ var sib_height = $(this).prev().height();
+ }
+ if ($.browser.msie && $.browser.version >= 8) {
+ sib_height = sib_height + 1;
+ }
+ $(this).css("height", sib_height);
+ $(this).css("position", "relative");
+ $(this).css("top", 0).css("left", 0);
+ // Remove the placeholder and hover class from the item
+ $(this).removeClass("g-hover-item");
+ $("#g-place-holder").remove();
+ }
+ );
+ }
+
+ // Photo/Item item view
+ if ($("#g-photo,#g-movie").length) {
+ // Ensure the resized image fits within its container
+ $("#g-photo,#g-movie").gallery_fit_photo();
+
+ // Initialize context menus
+ $("#g-photo,#g-movie").hover(function(){
+ $(this).gallery_context_menu();
+ });
+
+ // Add scroll effect for links to named anchors
+ $.localScroll({
+ queue: true,
+ duration: 1000,
+ hash: true
+ });
+
+ $(this).find(".g-dialog-link").gallery_dialog();
+ $(this).find(".g-ajax-link").gallery_ajax();
+ }
+
+ // Initialize button hover effect
+ $.fn.gallery_hover_init();
+
+});
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail.png
new file mode 100755
index 00000000..801976ba
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorContent.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorContent.png
new file mode 100755
index 00000000..85d5dda6
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorContent.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorDefault.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorDefault.png
new file mode 100755
index 00000000..e4ba7bd1
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorDefault.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorHeader.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorHeader.png
new file mode 100755
index 00000000..fba00029
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_bgColorHeader.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_borderColorDefault.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_borderColorDefault.png
new file mode 100755
index 00000000..e38bb48d
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_borderColorDefault.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcActive.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcActive.png
new file mode 100755
index 00000000..b1db8e2c
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcActive.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcDefault.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcDefault.png
new file mode 100755
index 00000000..450d826b
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcDefault.png differ
diff --git a/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcHeader.png b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcHeader.png
new file mode 100755
index 00000000..8c3dd3a5
Binary files /dev/null and b/modules/themeroller/data/masks/admin_thumbnail/thumbnail_fcHeader.png differ
diff --git a/modules/themeroller/data/masks/css/themeroller/ui-icons_mask_256x240.png b/modules/themeroller/data/masks/css/themeroller/ui-icons_mask_256x240.png
new file mode 100644
index 00000000..e941eda5
Binary files /dev/null and b/modules/themeroller/data/masks/css/themeroller/ui-icons_mask_256x240.png differ
diff --git a/modules/themeroller/data/masks/images/avatar_mask.png b/modules/themeroller/data/masks/images/avatar_mask.png
new file mode 100644
index 00000000..96c7e427
Binary files /dev/null and b/modules/themeroller/data/masks/images/avatar_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-album_mask.png b/modules/themeroller/data/masks/images/ico-album_mask.png
new file mode 100644
index 00000000..790c0d25
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-album_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-denied-active_mask.png b/modules/themeroller/data/masks/images/ico-denied-active_mask.png
new file mode 100644
index 00000000..fb5b9cdb
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-denied-active_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-denied-inactive_mask.png b/modules/themeroller/data/masks/images/ico-denied-inactive_mask.png
new file mode 100644
index 00000000..fb5b9cdb
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-denied-inactive_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-denied-passive_mask.png b/modules/themeroller/data/masks/images/ico-denied-passive_mask.png
new file mode 100644
index 00000000..fb5b9cdb
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-denied-passive_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-error_mask.png b/modules/themeroller/data/masks/images/ico-error_mask.png
new file mode 100644
index 00000000..b92f91f5
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-error_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-help_mask.png b/modules/themeroller/data/masks/images/ico-help_mask.png
new file mode 100644
index 00000000..254ef861
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-help_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-info_mask.png b/modules/themeroller/data/masks/images/ico-info_mask.png
new file mode 100644
index 00000000..70195548
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-info_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-lock_mask.png b/modules/themeroller/data/masks/images/ico-lock_mask.png
new file mode 100644
index 00000000..f14d037b
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-lock_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-print_mask.png b/modules/themeroller/data/masks/images/ico-print_mask.png
new file mode 100644
index 00000000..9f702d07
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-print_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-separator-rtl_mask.png b/modules/themeroller/data/masks/images/ico-separator-rtl_mask.png
new file mode 100755
index 00000000..1635f422
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-separator-rtl_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-separator_mask.png b/modules/themeroller/data/masks/images/ico-separator_mask.png
new file mode 100755
index 00000000..bc70f451
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-separator_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-success-active_mask.png b/modules/themeroller/data/masks/images/ico-success-active_mask.png
new file mode 100644
index 00000000..90cdfacb
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-success-active_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-success-inactive_mask.png b/modules/themeroller/data/masks/images/ico-success-inactive_mask.png
new file mode 100644
index 00000000..becd378a
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-success-inactive_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-success-passive_mask.png b/modules/themeroller/data/masks/images/ico-success-passive_mask.png
new file mode 100644
index 00000000..becd378a
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-success-passive_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-view-comments_mask.png b/modules/themeroller/data/masks/images/ico-view-comments_mask.png
new file mode 100644
index 00000000..884dcaf4
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-view-comments_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-view-fullsize_mask.png b/modules/themeroller/data/masks/images/ico-view-fullsize_mask.png
new file mode 100644
index 00000000..7f705558
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-view-fullsize_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-view-slideshow-rtl_mask.png b/modules/themeroller/data/masks/images/ico-view-slideshow-rtl_mask.png
new file mode 100644
index 00000000..b9bd783a
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-view-slideshow-rtl_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-view-slideshow_mask.png b/modules/themeroller/data/masks/images/ico-view-slideshow_mask.png
new file mode 100644
index 00000000..55c24a0f
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-view-slideshow_mask.png differ
diff --git a/modules/themeroller/data/masks/images/ico-warning_mask.png b/modules/themeroller/data/masks/images/ico-warning_mask.png
new file mode 100644
index 00000000..e2763911
Binary files /dev/null and b/modules/themeroller/data/masks/images/ico-warning_mask.png differ
diff --git a/modules/themeroller/data/masks/images/select-photos-backg_mask.png b/modules/themeroller/data/masks/images/select-photos-backg_mask.png
new file mode 100644
index 00000000..98924888
Binary files /dev/null and b/modules/themeroller/data/masks/images/select-photos-backg_mask.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail.png
new file mode 100755
index 00000000..3ae3d63b
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorContent.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorContent.png
new file mode 100755
index 00000000..63d4ffa4
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorContent.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorDefault.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorDefault.png
new file mode 100755
index 00000000..e3c6adb6
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorDefault.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorHeader.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorHeader.png
new file mode 100755
index 00000000..70d8e93e
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail_bgColorHeader.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail_fcDefault.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail_fcDefault.png
new file mode 100755
index 00000000..9fca446a
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail_fcDefault.png differ
diff --git a/modules/themeroller/data/masks/site_thumbnail/thumbnail_iconColorHover.png b/modules/themeroller/data/masks/site_thumbnail/thumbnail_iconColorHover.png
new file mode 100755
index 00000000..3a27fb6d
Binary files /dev/null and b/modules/themeroller/data/masks/site_thumbnail/thumbnail_iconColorHover.png differ
diff --git a/modules/themeroller/data/views/album.html.php b/modules/themeroller/data/views/album.html.php
new file mode 100644
index 00000000..de196be0
--- /dev/null
+++ b/modules/themeroller/data/views/album.html.php
@@ -0,0 +1,42 @@
+
+ // @todo Set hover on AlbumGrid list items for guest users ?>
+
+ = $theme->album_top() ?>
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+
+
+ if (count($children)): ?>
+ foreach ($children as $i => $child): ?>
+ $item_class = "g-photo"; ?>
+ if ($child->is_album()): ?>
+ $item_class = "g-album"; ?>
+ endif ?>
+
+ = $theme->thumb_top($child) ?>
+
+ = $child->thumb_img(array("class" => "g-thumbnail")) ?>
+
+ = $theme->thumb_bottom($child) ?>
+ = $theme->context_menu($child, "#g-item-id-{$child->id} .g-thumbnail") ?>
+
+
+
+ endforeach ?>
+ else: ?>
+ if ($user->admin || access::can("add", $item)): ?>
+ $addurl = url::site("uploader/index/$item->id") ?>
+ = t("There aren't any photos here yet! Add some .",
+ array("attrs" => html::mark_clean("href=\"$addurl\" class=\"g-dialog-link\""))) ?>
+ else: ?>
+ = t("There aren't any photos here yet!") ?>
+ endif; ?>
+ endif; ?>
+
+= $theme->album_bottom() ?>
+
+= $theme->paginator() ?>
diff --git a/modules/themeroller/data/views/block.html.php b/modules/themeroller/data/views/block.html.php
new file mode 100644
index 00000000..699d7c22
--- /dev/null
+++ b/modules/themeroller/data/views/block.html.php
@@ -0,0 +1,10 @@
+
+ if ($anchor): ?>
+
+ endif ?>
+
+
= $title ?>
+
+ = $content ?>
+
+
diff --git a/modules/themeroller/data/views/dynamic.html.php b/modules/themeroller/data/views/dynamic.html.php
new file mode 100644
index 00000000..a8a4d362
--- /dev/null
+++ b/modules/themeroller/data/views/dynamic.html.php
@@ -0,0 +1,29 @@
+
+
+
+
+ foreach ($children as $i => $child): ?>
+ ">
+ = $theme->thumb_top($child) ?>
+
+
+
+ = html::purify($child->title) ?>
+ = $theme->thumb_bottom($child) ?>
+
+
+ endforeach ?>
+
+= $theme->dynamic_bottom() ?>
+
+= $theme->paginator() ?>
diff --git a/modules/themeroller/data/views/movie.html.php b/modules/themeroller/data/views/movie.html.php
new file mode 100644
index 00000000..158857db
--- /dev/null
+++ b/modules/themeroller/data/views/movie.html.php
@@ -0,0 +1,19 @@
+
+
+ = $theme->photo_top() ?>
+
+ = $theme->paginator() ?>
+
+
+ = $theme->resize_top($item) ?>
+ = $item->movie_img(array("class" => "g-movie", "id" => "g-item-id-{$item->id}")) ?>
+ = $theme->resize_bottom($item) ?>
+
+
+
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+
+ = $theme->photo_bottom() ?>
+
diff --git a/modules/themeroller/data/views/no_sidebar.html.php b/modules/themeroller/data/views/no_sidebar.html.php
new file mode 100644
index 00000000..a9eb0e3e
--- /dev/null
+++ b/modules/themeroller/data/views/no_sidebar.html.php
@@ -0,0 +1,6 @@
+
+
diff --git a/modules/themeroller/data/views/page.html.php b/modules/themeroller/data/views/page.html.php
new file mode 100644
index 00000000..9f94b04f
--- /dev/null
+++ b/modules/themeroller/data/views/page.html.php
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+ if ($page_title): ?>
+ = $page_title ?>
+ else: ?>
+ if ($theme->item()): ?>
+ if ($theme->item()->is_album()): ?>
+ = t("Browse Album :: %album_title", array("album_title" => $theme->item()->title)) ?>
+ elseif ($theme->item()->is_photo()): ?>
+ = t("Photo :: %photo_title", array("photo_title" => $theme->item()->title)) ?>
+ else: ?>
+ = t("Movie :: %movie_title", array("movie_title" => $theme->item()->title)) ?>
+ endif ?>
+ elseif ($theme->tag()): ?>
+ = t("Browse Tag :: %tag_title", array("tag_title" => $theme->tag()->name)) ?>
+ else: /* Not an item, not a tag, no page_title specified. Help! */ ?>
+ = t("Gallery") ?>
+ endif ?>
+ endif ?>
+
+
" type="image/x-icon" />
+ = $theme->css("yui/reset-fonts-grids.css") ?>
+ = $theme->css("superfish/css/superfish.css") ?>
+ = $theme->css("themeroller/ui.base.css") ?>
+ = $theme->css("gallery.common.css") ?>
+ = $theme->css("screen.css") ?>
+
+ if ($theme->page_type == "collection"): ?>
+ if ($thumb_proportion != 1): ?>
+ $new_width = round($thumb_proportion * 213) ?>
+ $new_height = round($thumb_proportion * 240) ?>
+
+ endif ?>
+ endif ?>
+ = $theme->script("jquery.js") ?>
+ = $theme->script("jquery.form.js") ?>
+ = $theme->script("jquery-ui.js") ?>
+ = $theme->script("gallery.common.js") ?>
+ /* MSG_CANCEL is required by gallery.dialog.js */ ?>
+
+ = $theme->script("gallery.ajax.js") ?>
+ = $theme->script("gallery.dialog.js") ?>
+ = $theme->script("superfish/js/superfish.js") ?>
+ = $theme->script("jquery.localscroll.js") ?>
+ = $theme->script("ui.init.js") ?>
+
+ /* These are page specific, but if we put them before $theme->head() they get combined */ ?>
+ if ($theme->page_subtype == "photo"): ?>
+ = $theme->script("jquery.scrollTo.js") ?>
+ = $theme->script("gallery.show_full_size.js") ?>
+ elseif ($theme->page_subtype == "movie"): ?>
+ = $theme->script("flowplayer.js") ?>
+ endif ?>
+
+ = $theme->head() ?>
+
+
+ body_attributes() ?>>
+ = $theme->page_top() ?>
+
+ = $theme->site_status() ?>
+
+
+
+
+
+ = $theme->messages() ?>
+ = $content ?>
+
+
+
+
+
+
+
+ = $theme->page_bottom() ?>
+
+
diff --git a/modules/themeroller/data/views/paginator.html.php b/modules/themeroller/data/views/paginator.html.php
new file mode 100644
index 00000000..5034c965
--- /dev/null
+++ b/modules/themeroller/data/views/paginator.html.php
@@ -0,0 +1,87 @@
+
+
+// This is a generic paginator for album, photo and movie pages. Depending on the page type,
+// there are different sets of variables available. With this data, you can make a paginator
+// that lets you say "You're viewing photo 5 of 35", or "You're viewing photos 10 - 18 of 37"
+// for album views.
+//
+// Available variables for all page types:
+// $page_type - "collection", "item", or "other"
+// $page_subtype - "album", "movie", "photo", "tag", etc.
+// $previous_page_url - the url to the previous page, if there is one
+// $next_page_url - the url to the next page, if there is one
+// $total - the total number of photos in this album
+//
+// Available for the "collection" page types:
+// $page - what page number we're on
+// $max_pages - the maximum page number
+// $page_size - the page size
+// $first_page_url - the url to the first page, or null if we're on the first page
+// $last_page_url - the url to the last page, or null if we're on the last page
+// $first_visible_position - the position number of the first visible photo on this page
+// $last_visible_position - the position number of the last visible photo on this page
+//
+// Available for "item" page types:
+// $position - the position number of this photo
+//
+?>
+
+
+
+ if ($page_type == "collection"): ?>
+ if (isset($first_page_url)): ?>
+
+ = t("First") ?>
+ else: ?>
+
+ = t("First") ?>
+ endif ?>
+ endif ?>
+
+ if (isset($previous_page_url)): ?>
+
+ = t("Previous") ?>
+ else: ?>
+
+ = t("Previous") ?>
+ endif ?>
+
+
+
+ if ($total): ?>
+ if ($page_type == "collection"): ?>
+ = /* @todo This message isn't easily localizable */
+ t2("Photo %from_number of %count",
+ "Photos %from_number - %to_number of %count",
+ $total,
+ array("from_number" => $first_visible_position,
+ "to_number" => $last_visible_position,
+ "count" => $total)) ?>
+ else: ?>
+ = t("%position of %total", array("position" => $position, "total" => $total)) ?>
+ endif ?>
+ else: ?>
+ = t("No photos") ?>
+ endif ?>
+
+
+
+ if (isset($next_page_url)): ?>
+
+ = t("Next") ?>
+ else: ?>
+
+ = t("Next") ?>
+ endif ?>
+
+ if ($page_type == "collection"): ?>
+ if (isset($last_page_url)): ?>
+
+ = t("Last") ?>
+ else: ?>
+
+ = t("Last") ?>
+ endif ?>
+ endif ?>
+
+
diff --git a/modules/themeroller/data/views/photo.html.php b/modules/themeroller/data/views/photo.html.php
new file mode 100644
index 00000000..f8b5511c
--- /dev/null
+++ b/modules/themeroller/data/views/photo.html.php
@@ -0,0 +1,38 @@
+
+
+ if (access::can("view_full", $theme->item())): ?>
+
+
+ endif ?>
+
+
+ = $theme->photo_top() ?>
+
+ = $theme->paginator() ?>
+
+
+
+
+
= html::purify($item->title) ?>
+
= nl2br(html::purify($item->description)) ?>
+
+
+ = $theme->photo_bottom() ?>
+
diff --git a/modules/themeroller/data/views/sidebar.html.php b/modules/themeroller/data/views/sidebar.html.php
new file mode 100644
index 00000000..086d1359
--- /dev/null
+++ b/modules/themeroller/data/views/sidebar.html.php
@@ -0,0 +1,16 @@
+
+= $theme->sidebar_top() ?>
+
+
+= $theme->sidebar_blocks() ?>
+= $theme->sidebar_bottom() ?>
diff --git a/modules/themeroller/helpers/themeroller.php b/modules/themeroller/helpers/themeroller.php
new file mode 100644
index 00000000..35ca62fc
--- /dev/null
+++ b/modules/themeroller/helpers/themeroller.php
@@ -0,0 +1,181 @@
+open($zipfile) === true) {
+ $extract_path = VARPATH . trim($zipfile, "/") . ".d";
+ Session::instance()->set("theme_extract_path", $extract_path);
+ $zip->extractTo($extract_path);
+ $zip->close();
+ return $extract_path;
+ } else {
+ return false;
+ }
+ }
+
+ static function recursive_directory_delete($path) {
+ if (is_dir($path)) {
+ $objects = scandir($path);
+ foreach ($objects as $object) {
+ if ($object[0] != ".") {
+ $object_path = "$path/$object";
+ if (filetype($object_path) == "dir") {
+ self::recursive_directory_delete($object_path);
+ } else {
+ unlink($object_path);
+ }
+ }
+ }
+ }
+ }
+
+ static function get_theme_name($extract_path) {
+ $theme_name = null;
+ if ($handle = opendir($extract_path . "/css")) {
+ while (false !== ($file = readdir($handle))) {
+ if ($file[0] !== ".") {
+ $theme_name = basename($file);
+ break;
+ }
+ }
+ if (empty($theme_name)) {
+ Kohana_Log::add("error", "zip file: no theme name");
+ $post->add_error($field, "invalid zipfile");
+ }
+ closedir($handle);
+ }
+
+ return $theme_name;
+ }
+
+ static function get_theme_parameters($original_name, $css_path, $is_admin) {
+ $parameters = array();
+ $css_files = glob("$css_path/css/$original_name/jquery*.css");
+ $css_contents = file_get_contents($css_files[0]);
+ $parameters["colors"] = $parameters["icons"] = array();
+ if (preg_match("/[?|&](.*)/", $css_contents, $matches)) {
+ if (preg_match_all("/&{0,1}(\w+)=([a-zA-Z0-9\-_\%\.,]*)/", $matches[1], $colors, PREG_SET_ORDER)) {
+ foreach ($colors as $color) {
+ $parameters["colors"][$color[1]] = $color[2];
+ if (strpos($color[1], "icon") === 0) {
+ $parameters["icons"][] = $color[2];
+ }
+ }
+ }
+ }
+ $parameters["js"] = $is_admin ? glob(MODPATH . "themeroller/data/js/admin_*.js") :
+ glob(MODPATH . "themeroller/data/js/site_*.js");
+ $parameters["standard_css"] = glob(MODPATH . "themeroller/data/css/*.css");
+ $parameters["masks"] = glob(MODPATH . "themeroller/data/masks/images/*.png");
+ $parameters["icon_mask"] = MODPATH . "themeroller/data/masks/css/themeroller/ui-icons_mask_256x240.png";
+ $parameters["views"] = $is_admin ? glob(MODPATH . "themeroller/data/admin_views/*.html.php") :
+ glob(MODPATH . "themeroller/data/views/*.html.php");
+ $parameters["css_files"] = $css_files;
+ $parameters["images"] =
+ glob("$css_path/development-bundle/themes/$original_name/images/ui-bg*.png");
+ $thumb_dir = $is_admin ? "admin_thumbnail" : "site_thumbnail";
+ $parameters["thumbnail"] = MODPATH . "themeroller/data/masks/$thumb_dir/thumbnail.png";
+ $parts = glob(MODPATH . "themeroller/data/masks/$thumb_dir/thumbnail_*.png");
+ $parameters["thumbnail_parts"] = array();
+ foreach ($parts as $thumb_file) {
+ if (preg_match("/thumbnail_(.*)\.png$/", $thumb_file, $matches)) {
+ $parameters["thumbnail_parts"][] = array("file" => $thumb_file,
+ "color" => $parameters["colors"][$matches[1]]);
+ }
+ }
+
+ return $parameters;
+ }
+
+ static function generate_image($mask_file, $color, $target_dir, $replace_with="") {
+ $output = $target_dir . str_replace("mask", $replace_with, basename($mask_file));
+ $mask = imagecreatefrompng($mask_file);
+ $image = imagecreatetruecolor(imagesx($mask), imagesy($mask));
+ $icon_color = self::_rgb(hexdec($color));
+
+ $transparent = imagecolorallocatealpha($image,
+ $icon_color['red'], $icon_color['green'], $icon_color['blue'], 127);
+ imagefill($image, 0, 0, $transparent);
+ imagefilter($mask, IMG_FILTER_EDGEDETECT);
+
+ for ($y=0; $y < imagesy($mask); $y++) {
+ for ($x=0; $x < imagesx($mask); $x++) {
+ $pixel_color = imagecolorsforindex($mask, imagecolorat($mask, $x, $y));
+ $mask_color = self::_grayscale_pixel($pixel_color);
+ $mask_alpha = 127 - (floor($mask_color["red"] / 2) * (1 - ($pixel_color["alpha"] / 127)));
+ $new_color = imagecolorallocatealpha($image,
+ $icon_color['red'], $icon_color['green'], $icon_color['blue'], $mask_alpha);
+ imagesetpixel($image, $x, $y, $new_color);
+ }
+ }
+
+ imagesavealpha($image, true);
+ imagealphablending($image, false);
+ imagepng($image, $output);
+ imagedestroy($image);
+ imagedestroy($mask);
+ }
+
+ static function generate_thumbnail($base, $parts, $target) {
+ $image = imagecreatefrompng($base);
+
+ $transparent = imagecolorallocatealpha($image, 0, 0, 0, 127);
+ imagefill($image, 0, 0, $transparent);
+
+ $width = imagesx($image);
+ $height = imagesy($image);
+
+ foreach ($parts as $thumb_part) {
+ $color = self::_rgb(hexdec($thumb_part["color"]));
+ $image_part = imagecreatefrompng($thumb_part["file"]);
+ for ($y=0; $y < imagesy($image_part); $y++) {
+ for ($x=0; $x < imagesx($image_part); $x++) {
+ $pixel_color = imagecolorsforindex($image_part, imagecolorat($image_part, $x, $y));
+ $new_color = imagecolorallocatealpha($image,
+ $color['red'], $color['green'], $color['blue'], $pixel_color["alpha"]);
+ imagesetpixel($image, $x, $y, $new_color);
+ }
+ }
+ imagedestroy($image_part);
+ }
+
+ //$new_width = 200;
+ //$new_height = floor($height * $new_width / $width);
+
+ //$resized = imagecreatetruecolor($new_width, $new_height);
+ //imagecopyresampled($resized, $image, 0, 0, 0, 0,$new_width, $new_height, $width, $height);
+ imagesavealpha($image, true);
+ imagealphablending($image, false);
+ imagepng($image, $target);
+ imagedestroy($image);
+ }
+
+ private static function _rgb($color) {
+ $r = ($color >> 16) & 0xff;
+ $g = ($color >> 8) & 0xff;
+ $b = $color & 0xff;
+ return array("red" => $r, "green" => $g, "blue" => $b, "alpha" => 0);
+ }
+
+ private static function _grayscale_pixel($color) {
+ $gray = round(($color['red'] * 0.299) + ($color['green'] * 0.587) + ($color['blue'] * 0.114));
+ return array("red" => $gray, "green" => $gray, "blue" => $gray, "alpha" => 0);
+ }
+}
diff --git a/modules/themeroller/helpers/themeroller_event.php b/modules/themeroller/helpers/themeroller_event.php
new file mode 100644
index 00000000..302ed4b9
--- /dev/null
+++ b/modules/themeroller/helpers/themeroller_event.php
@@ -0,0 +1,27 @@
+get("appearance_menu")
+ ->append(Menu::factory("dialog")
+ ->id("themeroller")
+ ->label(t("Import themeroller"))
+ ->url(url::site("admin/themeroller/form_upload")));
+ }
+}
diff --git a/modules/themeroller/helpers/themeroller_installer.php b/modules/themeroller/helpers/themeroller_installer.php
new file mode 100644
index 00000000..5b59a982
--- /dev/null
+++ b/modules/themeroller/helpers/themeroller_installer.php
@@ -0,0 +1,35 @@
+get("mode", "init");
+ $start = microtime(true);
+ $theme_name = $task->get("theme_name");
+ $is_admin = $task->get("is_admin", false);
+ $theme_path = THEMEPATH . "$theme_name/";
+ $parameters = $task->get("parameters");
+ $completed = $task->get("completed", 0);
+ switch ($mode) {
+ case "init":
+ $views = glob(MODPATH . "themeroller/data/views/*.html.php");
+ $task->set("mode", "create_directory");
+ $parameters = themeroller::get_theme_parameters($task->get("original_name"),
+ $task->get("path"),
+ $is_admin);
+ $task->set("total_activites",
+ 7 // number of directories to create
+ + 3 // screen.css, theme.info, thumbnail
+ + count($parameters["standard_css"]) // number of standard css to copy
+ + count($parameters["views"]) // number of views to copy
+ + count($parameters["js"]) // number of javascript files to copy
+ + count($parameters["masks"]) // number of images to generate
+ + count($parameters["icons"]) // number of icon images to generate
+ + count($parameters["css_files"]) // number of css files
+ + count($parameters["images"])); // number of image files to copy
+
+ $task->status = t("Starting up");
+ break;
+ case "create_directory":
+ $completed = $task->get("completed");
+ foreach (array("", "css", "css/themeroller", "css/themeroller/images", "images",
+ "js", "views") as $dir) {
+ $path = "{$theme_path}$dir";
+ $completed++;
+ if (!file_exists($path)) {
+ mkdir($path);
+ chmod($path, 0755);
+ }
+ }
+ $task->status = t("Directory created");
+ $task->set("mode", "copy_views");
+ break;
+ case "copy_views":
+ $task->status = t("Copying views");
+ while (!empty($parameters["views"]) && microtime(true) - $start < 1.5) {
+ $view = array_shift($parameters["views"]);
+ $target = "{$theme_path}views/" . basename($view);
+ if (!file_exists($target)) {
+ copy($view, $target);
+ }
+ $completed++;
+ }
+
+ if (empty($parameters["views"])){
+ $task->status = t("Views copied");
+ $task->set("mode", "copy_themeroller_images");
+ }
+ break;
+ case "copy_themeroller_images":
+ $task->status = t("Copying themeroller images");
+ while (!empty($parameters["images"]) && microtime(true) - $start < 1.5) {
+ $image = array_shift($parameters["images"]);
+ $target = "{$theme_path}css/themeroller/images/" . basename($image);
+ if (!file_exists($target)) {
+ copy($image, $target);
+ }
+ $completed++;
+ }
+
+ if (empty($parameters["views"])){
+ $task->status = t("Themeroller images copied");
+ $task->set("mode", "copy_css");
+ }
+ break;
+ case "copy_css":
+ $task->status = t("Copying themeroller css");
+ $target = "{$theme_path}css/themeroller/ui.base.css";
+ copy($parameters["css_files"][0], $target);
+ $completed++;
+ $task->status = t("Themeroller css copied");
+ $task->set("mode", "generate_images");
+ break;
+ case "generate_images":
+ $task->status = t("Generating gallery images");
+ $target_dir = "{$theme_path}images/";
+ $colors = $task->get("colors");
+ $image_color = $colors["iconColorHover"];
+ while (!empty($parameters["masks"]) && microtime(true) - $start < 1.5) {
+ $mask = array_shift($parameters["masks"]);
+ themeroller::generate_image($mask, $image_color, $target_dir);
+ $completed++;
+ }
+ if (empty($parameters["masks"])) {
+ $task->set("mode", "generate_icons");
+ $task->status = t("Gallery images generated");
+ }
+ break;
+ case "generate_icons":
+ $task->status = t("Generating icons");
+ $target_dir = "{$theme_path}css/themeroller/images/";
+ while (!empty($parameters["icons"]) && microtime(true) - $start < 1.5) {
+ $color = array_shift($parameters["icons"]);
+ themeroller::generate_image($parameters["icon_mask"], $color, $target_dir, $color);
+ $completed++;
+ }
+ if (empty($parameters["icons"])) {
+ $task->set("mode", "copy_standard_css");
+ $task->status = t("Icons generated");
+ }
+ break;
+ case "copy_standard_css":
+ $task->status = t("Copying standard css");
+ while (!empty($parameters["standard_css"]) && microtime(true) - $start < 1.5) {
+ $css = array_shift($parameters["standard_css"]);
+ $target = "{$theme_path}css/" . basename($css);
+ if (!file_exists($target)) {
+ copy($css, $target);
+ }
+ $completed++;
+ }
+
+ if (empty($parameters["standard_css"])){
+ $task->status = t("Standard css copied");
+ $task->set("mode", "copy_javascript");
+ }
+ break;
+ case "copy_javascript":
+ $task->status = t("Copying javascript");
+ while (!empty($parameters["js"]) && microtime(true) - $start < 1.5) {
+ $js = array_shift($parameters["js"]);
+ $target = "{$theme_path}js/" . str_replace(array("admin_", "site_"), "", basename($js));
+ if (!file_exists($target)) {
+ copy($js, $target);
+ }
+ $completed++;
+ }
+
+ if (empty($parameters["js"])){
+ $task->status = t("Javascript copied");
+ $task->set("mode", "generate_screen_css");
+ }
+ break;
+ case "generate_screen_css":
+ $file = "{$theme_path}/css/screen.css";
+ $v = new View(($is_admin ? "admin" : "site") . "_screen.css");
+ $v->display_name = $task->get("display_name");
+ foreach ($parameters["colors"] as $color => $value) {
+ $v->$color = $value;
+ }
+ ob_start();
+ print $v->render();
+ file_put_contents($file, ob_get_contents());
+ ob_end_clean();
+ $completed++;
+ $task->status = t("Screen css generated");
+ $task->set("mode", "generate_thumbnail");
+ break;
+ case "generate_thumbnail":
+ themeroller::generate_thumbnail($parameters["thumbnail"],
+ $parameters["thumbnail_parts"],
+ "{$theme_path}thumbnail.png");
+ $task->status = t("Thumbnail generated");
+ $task->set("mode", "generate_theme_info");
+ $completed++;
+ break;
+ case "generate_theme_info":
+ $file = "{$theme_path}/theme.info";
+ $v = new View("theme.info");
+ $v->display_name = $task->get("display_name");
+ $v->description = $task->get("description");
+ $v->user_name = identity::active_user()->name;
+ $v->is_admin = $is_admin;
+ ob_start();
+ print $v->render();
+ file_put_contents($file, ob_get_contents());
+ ob_end_clean();
+ $completed++;
+ $task->status = t("Theme info generated");
+ $task->set("mode", "done");
+ break;
+ case "done":
+ themeroller::recursive_directory_delete($task->get("path"));
+ $display_name = $task->get("display_name");
+ $task->done = true;
+ $task->state = "success";
+ $task->percent_complete = 100;
+ $completed = $task->get("total_activites");
+ message::info(t("Successfully generated: %name", array("name" => $display_name)));
+ }
+ $task->set("completed", $completed);
+ $task->set("parameters", $parameters);
+ $task->percent_complete = ($completed / $task->get("total_activites")) * 100;
+ }
+
+}
\ No newline at end of file
diff --git a/modules/themeroller/module.info b/modules/themeroller/module.info
new file mode 100755
index 00000000..0e50286e
--- /dev/null
+++ b/modules/themeroller/module.info
@@ -0,0 +1,3 @@
+name = "Theme generator"
+description = "Use a JQuery UI theme to create a Gallery3 Theme"
+version = 1
diff --git a/modules/themeroller/views/admin_screen.css.php b/modules/themeroller/views/admin_screen.css.php
new file mode 100644
index 00000000..d41fc6a4
--- /dev/null
+++ b/modules/themeroller/views/admin_screen.css.php
@@ -0,0 +1,622 @@
+/**
+ * Gallery 3 Admin Redmond Theme Screen Styles
+ *
+ * @requires YUI reset, font, grids CSS
+ *
+ * Sheet organization:
+ * 1) Basic HTML elements
+ * 2) Reusable content blocks
+ * 3) Page layout containers
+ * 4) Content blocks in specific layout containers
+ * 5) Navigation and menus
+ * 6) jQuery and jQuery UI
+ * 7) Module color overrides
+ * 8) States and interactions
+ * 9) Right-to-left language styles
+ *
+ * @todo Review g-buttonset-vertical
+ */
+
+/** *******************************************************************
+ * 1) Basic HTML elements
+ **********************************************************************/
+html {
+ color: #2e6e9e; /* fcDefault; */
+}
+
+body, html {
+ background-color: #dfeffc; /* bgColorDefault */
+ font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; /* ffDefault */
+ font-size: 13px/1.231; /* fsDefault/ gallery_line_height */
+}
+
+p {
+ margin-bottom: 1em;
+}
+
+em {
+ font-style: oblique;
+}
+
+h1, h2, h3, h4, h5, strong, th {
+ font-weight: bold;
+}
+
+h1 {
+ font-size: 1.7em;
+}
+
+#g-dialog h1 {
+ font-size: 1.1em;
+}
+
+h2 {
+ font-size: 1.4em;
+}
+
+#g-sidebar .g-block h2 {
+ font-size: 1.2em;
+}
+
+#g-sidebar .g-block li {
+ margin-bottom: .6em;
+}
+
+h3 {
+ font-size: 1.2em;
+}
+
+/* Links ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+a,
+.g-menu a,
+#g-dialog a,
+.g-button,
+.g-button:active {
+ color: #2e6e9e !important; /* fcDefault; */
+ text-decoration: none;
+ -moz-outline-style: none;
+}
+
+a:hover,
+.g-button:hover,
+a.ui-state-hover,
+input.ui-state-hover,
+button.ui-state-hover {
+ color: #1d5987 !important; /* fcHover */
+ text-decoration: none;
+ -moz-outline-style: none;
+}
+
+a:hover,
+#g-dialog a:hover {
+ text-decoration: underline;
+}
+
+.g-menu a:hover {
+ text-decoration: none;
+}
+
+/* Forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+fieldset {
+ margin-bottom: 1em;
+}
+
+#g-content form ul li {
+ padding: .4em 0;
+}
+
+#g-dialog form {
+ width: 270px;
+}
+
+#g-dialog fieldset {
+ margin-bottom: 0;
+}
+
+/* Tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+table {
+ width: 100%;
+}
+
+#g-content table {
+ margin: .6em 0 2em 0;
+}
+
+caption,
+th {
+ text-align: left;
+}
+
+th,
+td {
+ border: none;
+ border-bottom: 1px solid #aaaaaa; /* borderColorContent */
+ padding: .5em;
+ vertical-align: middle;
+}
+
+th {
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+.g-even {
+ background-color: #fcfdfd; /* bgColorContent */
+}
+
+.g-odd {
+ background-color: #dfeffc; /* bgColorDefault */
+}
+
+/** *******************************************************************
+ * 2) Reusable content blocks
+ *********************************************************************/
+
+.g-block,
+#g-content #g-admin-dashboard .g-block {
+ border: 1px solid #aaaaaa; /* borderColorContent */
+ padding: 1em;
+}
+
+.g-block h2 {
+ padding: .3em .8em;
+}
+
+.g-block-content {
+ margin-top: 1em;
+}
+
+#g-content .g-block {
+ border: none;
+ padding: 0;
+}
+
+#g-sidebar .g-block-content {
+ padding: 0;
+}
+
+#g-content .g-selected,
+#g-content .g-available .g-block {
+ border: 1px solid #aaaaaa; /* borderColorContent */
+ padding: .8em;
+}
+
+.g-selected img,
+.g-available .g-block img {
+ float: left;
+ margin: 0 1em 1em 0;
+}
+
+.g-selected {
+ background: #f5f8f9 ; /* bgColorActive */
+}
+
+.g-available .g-installed-toolkit:hover {
+ cursor: pointer;
+ background: #fcfdfd; /* bgColorContent */
+}
+
+.g-available .g-button {
+ width: 96%;
+}
+
+.g-selected .g-button {
+ display: none;
+}
+
+.g-unavailable {
+ border-color: #ffffff; /* fcHeader; */;
+ opacity: 0.4;
+}
+
+.g-info td {
+ background-color: transparent;
+ background-image: none;
+}
+
+.g-success td {
+ background-color: transparent;
+ background-image: none;
+}
+
+.g-error td {
+ background-color: #cd0a0a /* borderColorError */;
+ color: #cd0a0a /* fcError */;
+ background-image: none;
+}
+
+.g-warning td {
+ background-color: #fcf9ce;
+ background-image: none;
+}
+
+.g-module-status.g-info,
+#g-log-entries .g-info,
+.g-module-status.g-success,
+#g-log-entries .g-success {
+ background-color: #fcfdfd /* bgColorContent */;
+}
+
+/*** ******************************************************************
+ * 3) Page layout containers
+ *********************************************************************/
+
+/* Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-header #g-login-menu {
+ margin-top: 1em;
+ float: right;
+}
+
+/* View container ~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.g-view {
+ background-color: #fcfdfd; /* bgColorContent */
+ border: 1px solid #a6c9e2; /* borderColorContent */
+ border-bottom: none;
+ min-width: 974px !important;
+}
+
+/* Layout containers ~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-header {
+ background-color: #5c9ccc; /* bgColorHeader */
+ border-bottom: 1px solid #4297d7; /* borderColorHeader */
+ color: #ffffff; /* fcHeader */
+ font-size: .8em;
+ margin-bottom: 20px;
+ padding: 0 20px;
+ position: relative;
+}
+
+#g-content {
+ font-size: 1.1em;
+ padding: 0 2em;
+ width: 96%;
+}
+
+#g-sidebar {
+ background-color: #fff;
+ font-size: .9em;
+ padding: 0 20px;
+ width: 220px;
+}
+
+#g-footer {
+ background-color: #5c9ccc; /* bgColorHeader */
+ border-top: 1px solid #4297d7; /* borderColorHeader */
+ color: #ffffff; /* fcHeader */
+ font-size: .8em;
+ margin-top: 20px;
+ padding: 10px 20px;
+}
+
+/** *******************************************************************
+ * 4) Content blocks in specific layout containers
+ *********************************************************************/
+
+/* Header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-header #g-logo {
+ background: transparent url('../../../lib/images/logo.png') no-repeat 0 .5em;
+ color: #ffffff /* fcHeader */ !important;
+ display: block;
+ height: 65px;
+ padding-top: 5px;
+ width: 105px;
+}
+
+#g-header #g-logo:hover {
+ color: #1d5987 !important; /* fcHover */
+ text-decoration: none;
+}
+
+#g-content .g-block h2 {
+ background-color: transparent;
+ padding-left: 0;
+}
+
+#g-sidebar .g-block-content {
+ padding-left: 1em;
+}
+
+.g-block .ui-dialog-titlebar {
+ margin: -1em -1em 0;
+}
+
+#g-sidebar .g-block h2 {
+ background: none;
+}
+
+/* Photo stream ~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-photo-stream {
+}
+
+#g-photo-stream .g-block-content ul {
+ border-right: 1px solid #e8e8e8;
+ height: 135px;
+ overflow: auto;
+ overflow: -moz-scrollbars-horizontal; /* for FF */
+ overflow-x: scroll; /* scroll horizontal */
+ overflow-y: hidden; /* Hide vertical*/
+}
+
+#g-content #g-photo-stream .g-item {
+ background-color: #dfeffc; /* bgColorDefault */
+ border: 1px solid #e8e8e8;
+ border-right-color: #ccc;
+ border-bottom-color: #ccc;
+ float: left;
+ height: 90px;
+ overflow: hidden;
+ text-align: center;
+ width: 90px;
+}
+
+#g-content .g-item {
+ background-color: #dfeffc; /* bgColorDefault */
+ border: 1px solid #e8e8e8;
+ border-right-color: #ccc;
+ border-bottom-color: #ccc;
+ height: 90px;
+ padding: 14px 8px;
+ text-align: center;
+ width: 90px;
+}
+
+/* Graphics settings ~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-admin-graphics .g-available .g-block {
+ clear: none;
+ float: left;
+ margin-right: 1em;
+ width: 30%;
+}
+
+/* Appearance settings ~~~~~~~~~~~~~~~~~~~ */
+
+#g-site-theme,
+#g-admin-theme {
+ float: left;
+ width: 48%;
+}
+
+#g-site-theme {
+ margin-right: 1em;
+}
+
+/* Block admin ~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.g-admin-blocks-list {
+ float: left;
+ margin: 0 2em 2em 0;
+ width: 30%;
+}
+
+.g-admin-blocks-list div:last-child {
+ border: .1em solid;
+ height: 100%;
+}
+
+.g-admin-blocks-list ul {
+ height: 98%;
+ margin: .1em .1em;
+ padding: .1em;
+}
+
+.g-admin-blocks-list ul li.g-draggable {
+ background-color: #dfeffc; /* bgColorDefault */
+ margin: .5em;
+ padding: .3em .8em;
+}
+
+/* In-line editing ~~~~~~~~~~~~~~~~~~~~~~ */
+#g-in-place-edit-message {
+ background-color: #fcfdfd; /* bgColorContent */
+}
+
+/* Theme options ~~~~~~~~~~~~~~~~~~~~~~~~ */
+#g-theme-options-form {
+ border: 1px solid #aaaaaa; /* borderColorContent */
+}
+#g-theme-options-form-tabs {
+ border: none !important;
+}
+#g-theme-options-form fieldset {
+ border: none;
+}
+
+.ui-tabs .ui-tabs-nav li a {
+ padding: 0 1em;
+}
+
+.ui-tabs .ui-tabs-nav li a.g-error {
+ background: none no-repeat scroll 0 0 transparent;
+ color: #cd0a0a !important; /* fcError */
+}
+
+/** *******************************************************************
+ * 5) Navigation and menus
+ *********************************************************************/
+
+/* Site Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-site-admin-menu {
+ bottom: 0;
+ font-size: 1.2em;
+ left: 140px;
+ position: absolute;
+}
+
+#g-site-admin-menu ul {
+ margin-bottom: 0;
+}
+
+/** *******************************************************************
+ * 6) jQuery and jQuery UI
+ *********************************************************************/
+
+/* Superfish menu overrides ~~~~~~~~~~~~~~ */
+.sf-menu a {
+ border-left:1px solid #a6c9e2; /* borderColorContent */
+}
+
+.sf-menu li,
+.sf-menu li li,
+.sf-menu li li ul li {
+ background-color: #dfeffc; /* bgColorDefault */
+}
+
+.sf-menu li:hover {
+ background-color: #d0e5f5; /* bgColorHover */
+}
+
+.sf-menu li:hover,
+.sf-menu li.sfHover,
+.sf-menu a:focus,
+.sf-menu a:hover,
+.sf-menu a:active {
+ background-color: #d0e5f5 !important; /* bgColorHover */
+}
+
+.sf-sub-indicator {
+ background-image: url("themeroller/images/ui-icons_2e83ff_256x240.png");
+ height: 16px;
+ width: 16px;
+}
+
+a > .sf-sub-indicator {
+ background-position: -64px -16px !important;
+ top: 0.6em;
+}
+
+.sf-menu ul a > .sf-sub-indicator {
+ background-position: -32px -16px !important;
+}
+
+/* jQuery UI Dialog ~~~~~~~~~~~~~~~~~~~~~~ */
+
+#g-admin-dashboard .ui-state-highlight,
+#g-sidebar .ui-state-highlight {
+ height: 2em;
+ margin-bottom: 1em;
+}
+
+.g-buttonset-vertical a {
+ width: 8em !important;
+}
+
+#g-admin-dashboard .ui-dialog-titlebar,
+#g-admin-dashboard-sidebar .ui-dialog-titlebar {
+ padding: .2em .4em;
+}
+
+/** *******************************************************************
+ * 7) Module color overrides
+ *********************************************************************/
+
+/* User admin form ~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#g-user-admin-list .g-admin {
+ color: #2e6e9e !important; /* fcDefault; */
+ font-weight: bold;
+}
+
+.g-group {
+ border: 1px solid #aaaaaa !important; /* borderColorContent */
+}
+
+.g-group h4 {
+ background-color: #dfeffc !important; /* bgColorDefault */
+ border-bottom: 1px dashed #2e6e9e !important; /* fcDefault; */
+}
+
+.g-default-group h4,
+.g-default-group .g-user {
+ color: #2e6e9e !important; /* fcDefault; */
+}
+
+/** *******************************************************************
+ * 8) States and interactions
+ *********************************************************************/
+
+.g-draggable:hover {
+ border: 1px dashed #fbec88; /* bgColorHighlight */
+}
+
+.ui-sortable .g-target,
+.ui-state-highlight {
+ background-color: #fbec88; /* bgColorHighlight */
+ border: 2px dotted #fad42e; /* borderColorHighlight */
+}
+
+/** *******************************************************************
+ * 9) Right to left styles
+ *********************************************************************/
+
+.rtl #g-content #g-album-grid .g-item,
+.rtl #g-site-theme,
+.rtl #g-admin-theme,
+.rtl .g-selected img,
+.rtl .g-available .g-block img,
+.rtl #g-content #g-photo-stream .g-item,
+.rtl li.g-group,
+.rtl #g-server-add-admin {
+ float: right;
+}
+
+.rtl #g-admin-graphics .g-available .g-block {
+ float: right;
+ margin-left: 1em;
+ margin-right: 0em;
+}
+
+.rtl #g-site-admin-menu {
+ left: auto;
+ right: 150px;
+}
+
+.rtl #g-header #g-login-menu {
+ float: left;
+}
+
+.rtl #g-header #g-login-menu li {
+ margin-left: 0;
+ padding-left: 0;
+ padding-right: 1.2em;
+}
+
+.rtl .g-selected img,
+.rtl .g-available .g-block img {
+ margin: 0 0 1em 1em;
+}
+
+/* RTL Superfish ~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.rtl .sf-menu a {
+ border-right:1px solid #fff;
+}
+
+.rtl .sf-sub-indicator {
+ background: url("themeroller/images/ui-icons_2e83ff_256x240.png") no-repeat -96px -16px; /* 8-bit indexed alpha png. IE6 gets solid image only */
+}
+
+/*** shadows for all but IE6 ***/
+.rtl .sf-shadow ul {
+ background: url('../images/superfish-shadow.png') no-repeat bottom left;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 0;
+ -moz-border-radius-topright: 0;
+ -moz-border-radius-bottomleft: 0;
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-bottom-left-radius: 0;
+ -moz-border-radius-topleft: 17px;
+ -moz-border-radius-bottomright: 17px;
+ -webkit-border-top-left-radius: 17px;
+ -webkit-border-bottom-right-radius: 17px;
+ border-top-left-radius: 17px;
+ border-bottom-right-radius: 17px;
+}
diff --git a/modules/themeroller/views/admin_themeroller_progress.html.php b/modules/themeroller/views/admin_themeroller_progress.html.php
new file mode 100644
index 00000000..8bfd05ab
--- /dev/null
+++ b/modules/themeroller/views/admin_themeroller_progress.html.php
@@ -0,0 +1,64 @@
+
+
+
+
+
= $task->name ?>
+
+
+ = t("Starting up...") ?>
+
+
+ = t("Pause") ?>
+ = t("Close") ?>
+
+
diff --git a/modules/themeroller/views/admin_themeroller_upload.html.php b/modules/themeroller/views/admin_themeroller_upload.html.php
new file mode 100755
index 00000000..b3cc86ec
--- /dev/null
+++ b/modules/themeroller/views/admin_themeroller_upload.html.php
@@ -0,0 +1,65 @@
+
+
+
+
+