diff --git a/installer/installer.php b/installer/installer.php
index 456cffaa..50657d80 100644
--- a/installer/installer.php
+++ b/installer/installer.php
@@ -104,11 +104,13 @@ class installer {
mysql_select_db($config["dbname"]);
}
- static function verify_version($config) {
+ static function verify_mysql_version($config) {
+ return version_compare(installer::mysql_version($config), "5.0.0", ">=");
+ }
+
+ static function mysql_version($config) {
$result = mysql_query("SHOW VARIABLES WHERE variable_name = \"version\"");
- $row = mysql_fetch_object($result);
- $version = substr($row->Value, 0, strpos($row->Value, "-"));
- return version_compare($version, "5.0.0", ">=");
+ return $row->Value;
}
static function db_empty($config) {
diff --git a/installer/views/invalid_db_version.html.php b/installer/views/invalid_db_version.html.php
index 8776ac35..5b021ba2 100644
--- a/installer/views/invalid_db_version.html.php
+++ b/installer/views/invalid_db_version.html.php
@@ -1,5 +1,5 @@
- The MySql database that you are referencing is less than the minimum version of 5.0.0.
+ Gallery requires at least MySQL version 5.0.0. You're using version = installer::mysql_version($config) ?>
diff --git a/installer/web.php b/installer/web.php
index aceb5368..eb0211a6 100644
--- a/installer/web.php
+++ b/installer/web.php
@@ -41,7 +41,7 @@ if (installer::already_installed()) {
if (!installer::connect($config)) {
$content = render("invalid_db_info.html.php");
- } else if (!installer::verify_version($config)) {
+ } else if (!installer::verify_mysql_version($config)) {
$content = render("invalid_db_version.html.php");
} else if (!installer::select_db($config)) {
$content = render("missing_db.html.php");
diff --git a/lib/gallery.common.css b/lib/gallery.common.css
new file mode 100644
index 00000000..ca90a484
--- /dev/null
+++ b/lib/gallery.common.css
@@ -0,0 +1,111 @@
+/* ####### states, interactions, positioning ########### */
+
+/* states */
+
+.g-active, .g-enabled, .g-available, .g-editable, .g-selected, .g-highlight {
+ font-weight: bold;
+}
+.g-inactive, .g-disabled, .g-unavailable, .g-uneditable, .g-locked, .g-unselected, .g-understate {
+ color: #ccc;
+ font-weight: normal;
+}
+
+.g-error, .g-denied {
+
+}
+.g-success, .g-allowed {
+
+}
+.g-info {
+
+}
+.g-warning {
+
+}
+
+.g-open {
+
+}
+.g-closed {
+
+}
+
+.g-installed {
+
+}
+.g-default {
+
+}
+
+/* interactions */
+
+.g-draggable, .ui-draggable {
+ cursor: move;
+}
+.g-target {
+
+}
+
+
+
+/* positioning */
+
+.g-right {
+ float: right;
+}
+.g-left {
+ float: left;
+}
+
+/* order */
+
+.g-first {
+
+}
+.g-last {
+
+}
+.g-even-row {
+
+}
+.g-odd-row {
+
+}
+
+/* text */
+
+.g-txt-small {
+ font-size: .8em;
+}
+.g-txt-big {
+ font-size: 1.2em;
+}
+.g-txt-right {
+ text-align: right;
+}
+
+/* ####### reusable containers/widgets ########### */
+
+.g-dialog {
+
+}
+
+.g-button { /* a link styled like a button */
+
+}
+
+.g-progressbar {
+
+}
+
+.g-block {
+
+}
+
+.g-message-box {
+
+}
+
+.g-list-horizontal {
+
+}
diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js
index 67f3f02d..39c451e3 100644
--- a/lib/gallery.dialog.js
+++ b/lib/gallery.dialog.js
@@ -76,6 +76,7 @@
var eCancel = '
_
- ">X
+ for_html_attr() ?>"
+ href="= html::clean_attribute(url::site("l10n_client/toggle_l10n_mode?csrf=".access::csrf_token())) ?>">X
= t("Page Text") ?>
if (!Input::instance()->get('show_all_l10n_messages')): ?>
@@ -76,5 +77,7 @@
var MSG_CLOSE_X = = t("X")->for_js() ?>;
var l10n_client_data = = json_encode($string_list) ?>;
var plural_forms = = json_encode($plural_forms) ?>;
+ var toggle_l10n_mode_url = = html::js_string(url::site("l10n_client/toggle_l10n_mode")) ?>;
+ var csrf = = html::js_string(access::csrf_token()) ?>;
diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php
index 2b966657..27299e85 100644
--- a/modules/organize/controllers/organize.php
+++ b/modules/organize/controllers/organize.php
@@ -25,7 +25,7 @@ class Organize_Controller extends Controller {
$v = new View("organize_dialog.html");
$v->album = $album;
- $v->album_tree = self::_tree($album);
+ $v->album_tree = self::_expanded_tree(ORM::factory("item", 1), $album);
$v->micro_thumb_grid = self::_get_micro_thumb_grid($album, 0);
print $v;
}
@@ -46,11 +46,14 @@ class Organize_Controller extends Controller {
$album = ORM::factory("item", $album_id);
foreach ($this->input->post("source_ids") as $source_id) {
- item::move(ORM::factory("item", $source_id), $album);
+ $source = ORM::factory("item", $source_id);
+ if (!$album->is_descendant($source)) {
+ item::move($source, $album);
+ }
}
print json_encode(
- array("tree" => self::_tree($album)->__toString(),
+ array("tree" => self::_expanded_tree(ORM::factory("item", 1), $album)->__toString(),
"grid" => self::_get_micro_thumb_grid($album, 0)->__toString()));
}
@@ -132,17 +135,22 @@ class Organize_Controller extends Controller {
return $v;
}
- private static function _tree($album) {
+ public function tree($album_id) {
+ $album = ORM::factory("item", $album_id);
+ access::required("view", $album);
+
+ print self::_expanded_tree($album);
+ }
+
+ /**
+ * Create an HTML representation of the tree from the root down to the selected album. We only
+ * include albums along the descendant hierarchy that includes the selected album, and the
+ * immediate child albums.
+ */
+ private static function _expanded_tree($root, $selected_album=null) {
$v = new View("organize_tree.html");
- $v->parents = $album->parents();
- $v->album = $album;
-
- if ($album->id == 1) {
- $v->peers = array($album);
- } else {
- $v->peers = $album->parent()->children(null, 0, array("type" => "album"));
- }
-
+ $v->album = $root;
+ $v->selected = $selected_album;
return $v;
}
}
diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css
index 85168810..4a65d20e 100644
--- a/modules/organize/css/organize.css
+++ b/modules/organize/css/organize.css
@@ -2,10 +2,6 @@
/*******************************************************************
* Dialog wide stylings
*/
-#gOrganizeDialog {
- text-align: left;
-}
-
#gOrganize {
overflow: hidden;
}
@@ -51,7 +47,7 @@
padding-left: 1.2em;
}
-.gAlbumText:hover {
+.gOrganizeAlbumText:hover {
border: 1px dashed #999;
padding: 1px;
}
@@ -67,14 +63,14 @@
cursor: pointer;
}
-.gAlbumText {
+.gOrganizeAlbumText {
cursor: pointer;
width: auto;
}
/*******************************************************************
* Album Panel Styles
*/
-#gMicroThumbPanel {
+#gOrganizeMicroThumbPanel {
margin: 0 !important;
padding: 0 !important;
background-color: #cfdeff;
@@ -85,11 +81,11 @@
overflow-y: auto;
}
-#gMicroThumbGrid {
+#gOrganizeMicroThumbGrid {
padding: 1em;
}
-.gMicroThumbGridCell {
+.gOrganizeMicroThumbGridCell {
float: left;
font-size: 0.8em;
padding: .5em !important;
@@ -98,14 +94,14 @@
border-right: 1px hidden #13A;
}
-.gMicroThumb {
+.gOrganizeMicroThumb {
display: block;
height: 9em;
text-align: center;
width: 9em;
}
-.gMicroThumbGridCell.ui-state-selected {
+.gOrganizeMicroThumbGridCell.ui-state-selected {
opacity: 1;
}
@@ -118,11 +114,11 @@
padding: .5em;
}
-#gMicroThumbPanel #gMicroThumbGrid .gAlbum {
+#gOrganizeMicroThumbPanel #gOrganizeMicroThumbGrid .gAlbum {
background-color: #e8e8e8;
}
-#gMicroThumbPanel #gMicroThumbGrid :hover {
+#gOrganizeMicroThumbPanel #gOrganizeMicroThumbGrid :hover {
opacity: 1;
}
diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js
index 04e14a2f..edafae61 100644
--- a/modules/organize/js/organize.js
+++ b/modules/organize/js/organize.js
@@ -4,7 +4,7 @@
handle: ".ui-state-selected",
distance: 10,
cursorAt: { left: -10, top: -10},
- appendTo: "#gMicroThumbPanel",
+ appendTo: "#gOrganizeMicroThumbPanel",
helper: function(event, ui) {
var selected = $(".ui-draggable.ui-state-selected img");
if (selected.length) {
@@ -37,16 +37,16 @@
},
start: function(event, ui) {
- $("#gMicroThumbPanel .ui-state-selected").hide();
+ $("#gOrganizeMicroThumbPanel .ui-state-selected").hide();
},
drag: function(event, ui) {
- var top = $("#gMicroThumbPanel").offset().top;
- var height = $("#gMicroThumbPanel").height();
+ var top = $("#gOrganizeMicroThumbPanel").offset().top;
+ var height = $("#gOrganizeMicroThumbPanel").height();
if (ui.offset.top > height + top - 20) {
- $("#gMicroThumbPanel").get(0).scrollTop += 100;
+ $("#gOrganizeMicroThumbPanel").get(0).scrollTop += 100;
} else if (ui.offset.top < top + 20) {
- $("#gMicroThumbPanel").get(0).scrollTop = Math.max(0, $("#gMicroThumbPanel").get(0).scrollTop - 100);
+ $("#gOrganizeMicroThumbPanel").get(0).scrollTop = Math.max(0, $("#gOrganizeMicroThumbPanel").get(0).scrollTop - 100);
}
}
},
@@ -74,7 +74,7 @@
drop: function(event, ui) {
if ($(event.target).hasClass("gViewOnly")) {
$(".ui-state-selected").show();
- $(".gMicroThumbGridCell").css("borderStyle", "none");
+ $(".gOrganizeMicroThumbGridCell").css("borderStyle", "none");
} else {
$.organize.do_drop({
url: move_url.replace("__ALBUM_ID__", $(event.target).attr("ref")),
@@ -85,7 +85,7 @@
},
do_drop: function(options) {
- $("#gMicroThumbPanel").selectable("destroy");
+ $("#gOrganizeMicroThumbPanel").selectable("destroy");
var source_ids = [];
$(options.source).each(function(i) {
source_ids.push($(this).attr("ref"));
@@ -104,7 +104,7 @@
$("#gOrganizeAlbumTree").html(data.tree);
}
if (data.grid) {
- $("#gMicroThumbGrid").html(data.grid);
+ $("#gOrganizeMicroThumbGrid").html(data.grid);
$("#gOrganizeSortColumn").attr("value", data.sort_column);
$("#gOrganizeSortOrder").attr("value", data.sort_order);
}
@@ -113,7 +113,7 @@
mouse_move_handler: function(event) {
if ($(".gDragHelper").length) {
- $(".gMicroThumbGridCell").css("borderStyle", "hidden");
+ $(".gOrganizeMicroThumbGridCell").css("borderStyle", "hidden");
$(".currentDropTarget").removeClass("currentDropTarget");
var borderStyle = event.pageX < $(this).offset().left + $(this).width() / 2 ?
"borderLeftStyle" : "borderRightStyle";
@@ -132,7 +132,7 @@
$("#gDialog").dialog("option", "zIndex", 70);
$("#gDialog").bind("dialogopen", function(event, ui) {
$("#gOrganize").height($("#gDialog").innerHeight() - 20);
- $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90);
+ $("#gOrganizeMicroThumbPanel").height($("#gDialog").innerHeight() - 90);
$("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 59);
});
@@ -152,15 +152,41 @@
},
set_handlers: function() {
- $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"});
- $("#gMicroThumbPanel").droppable($.organize.content_droppable);
+ $("#gOrganizeMicroThumbPanel").selectable({filter: ".gOrganizeMicroThumbGridCell"});
+ $("#gOrganizeMicroThumbPanel").droppable($.organize.content_droppable);
- $(".gMicroThumbGridCell").draggable($.organize.micro_thumb_draggable);
- $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler);
+ $(".gOrganizeMicroThumbGridCell").draggable($.organize.micro_thumb_draggable);
+ $(".gOrganizeMicroThumbGridCell").mousemove($.organize.mouse_move_handler);
$(".gOrganizeAlbum").droppable($.organize.branch_droppable);
- $(".gAlbumText").click($.organize.show_album);
+ $(".gOrganizeAlbumText").click($.organize.show_album);
+ $("#gOrganizeAlbumTree .ui-icon-plus,#gOrganizeAlbumTree .ui-icon-minus").click($.organize.toggle_branch);
},
+ toggle_branch: function(event) {
+ event.preventDefault();
+ var target = $(event.currentTarget);
+ var branch = $(target).parent();
+ var id = $(event.currentTarget).parent().attr("ref");
+
+ if ($(target).hasClass("ui-icon-plus")) {
+ // Expanding
+ if (!branch.find("ul").length) {
+ $.get(tree_url.replace("__ALBUM_ID__", id), { },
+ function(data) {
+ branch.replaceWith(data);
+ $.organize.set_handlers();
+ }
+ );
+ } else {
+ branch.find("ul:eq(0)").slideDown();
+ }
+ } else {
+ // Contracting
+ branch.find("ul:eq(0)").slideUp();
+ }
+ $(target).toggleClass("ui-icon-plus");
+ $(target).toggleClass("ui-icon-minus");
+ },
/**
* When the text of a selection is clicked, then show that albums contents
@@ -174,14 +200,14 @@
if ($(parent).hasClass("gViewOnly")) {
return;
}
- $("#gMicroThumbPanel").selectable("destroy");
+ $("#gOrganizeMicroThumbPanel").selectable("destroy");
var id = $(event.currentTarget).attr("ref");
$("#gOrganizeAlbumTree .selected").removeClass("selected");
- $(".gAlbumText[ref=" + id + "]").addClass("selected");
- var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0);
+ $(".gOrganizeAlbumText[ref=" + id + "]").addClass("selected");
+ var url = $("#gOrganizeMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0);
$.get(url, {},
function(data) {
- $("#gMicroThumbGrid").html(data.grid);
+ $("#gOrganizeMicroThumbGrid").html(data.grid);
$("#gOrganizeSortColumn").attr("value", data.sort_column);
$("#gOrganizeSortOrder").attr("value", data.sort_order);
$.organize.set_handlers();
@@ -199,7 +225,7 @@
.replace("__DIR__", dir);
$.get(url, {},
function(data) {
- $("#gMicroThumbGrid").html(data.grid);
+ $("#gOrganizeMicroThumbGrid").html(data.grid);
$("#gOrganizeSortColumn").attr("value", data.sort_column);
$("#gOrganizeSortOrder").attr("value", data.sort_order);
$.organize.set_handlers();
diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php
index 857499aa..cbc2e4f9 100644
--- a/modules/organize/views/organize_dialog.html.php
+++ b/modules/organize/views/organize_dialog.html.php
@@ -3,6 +3,7 @@
var move_url = "= url::site("organize/move_to/__ALBUM_ID__?csrf=$csrf") ?>";
var rearrange_url = "= url::site("organize/rearrange/__TARGET_ID__/__BEFORE__?csrf=$csrf") ?>";
var sort_order_url = "= url::site("organize/sort_order/__ALBUM_ID__/__COL__/__DIR__?csrf=$csrf") ?>";
+ var tree_url = "= url::site("organize/tree/__ALBUM_ID__") ?>";
= t("Organize %name", array("name" => html::purify($album->title))) ?>
@@ -22,9 +23,9 @@
-
diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php
index 31dc9af5..929d9ec3 100644
--- a/modules/organize/views/organize_thumb_grid.html.php
+++ b/modules/organize/views/organize_thumb_grid.html.php
@@ -1,8 +1,8 @@
foreach ($album->children(25, $offset) as $child): ?>
-
- ">
+
+ ">
= $child->thumb_img(array("class" => "gThumbnail", "ref" => $child->id), 90, true) ?>
@@ -13,7 +13,7 @@
setTimeout(function() {
$.get("= url::site("organize/content/$album->id/" . ($offset + 25)) ?>",
function(data) {
- $("#gMicroThumbGrid").append(data);
+ $("#gOrganizeMicroThumbGrid").append(data);
$.organize.set_handlers();
}
);
diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php
index 5b676889..50c202b0 100644
--- a/modules/organize/views/organize_tree.html.php
+++ b/modules/organize/views/organize_tree.html.php
@@ -1,44 +1,29 @@
- foreach ($parents as $parent): ?>
-
"
- ref="= $parent->id ?>">
+"
+ ref="= $album->id ?>">
-
- = html::clean($parent->title) ?>
+
+ "
+ ref="= $album->id ?>">
+ = html::clean($album->title) ?>
-
- endforeach ?>
-
- foreach ($peers as $peer): ?>
- - "
- ref="= $peer->id ?>">
- ">
+
+ foreach ($album->children(null, 0, array("type" => "album")) as $child): ?>
+ if ($selected && $child->is_descendant($selected)): ?>
+ = View::factory("organize_tree.html", array("selected" => $selected, "album" => $child)); ?>
+ else: ?>
+ - "
+ ref="= $child->id ?>">
+
- "
- ref="= $peer->id ?>">
- = html::clean($peer->title) ?>
+
+ = html::clean($child->title) ?>
-
- if ($peer->id == $album->id): ?>
-
- foreach ($album->children(null, 0, array("type" => "album")) as $child): ?>
- - "
- ref="= $child->id ?>">
-
-
-
- = html::clean($child->title) ?>
-
-
- endforeach ?>
-
- endif ?>
+ endif ?>
endforeach ?>
-
- foreach ($parents as $parent): ?>
- endforeach ?>
+
diff --git a/modules/search/helpers/search_task.php b/modules/search/helpers/search_task.php
index 5643573a..9508f420 100644
--- a/modules/search/helpers/search_task.php
+++ b/modules/search/helpers/search_task.php
@@ -48,12 +48,18 @@ class search_task_Core {
->where("search_records.item_id", null)
->orwhere("search_records.dirty", 1)
->find_all() as $item) {
- if (microtime(true) - $start > 1.5) {
- break;
+ // The query above can take a long time, so start the timer after its done
+ // to give ourselves a little time to actually process rows.
+ if (!isset($start)) {
+ $start = microtime(true);
}
search::update($item);
$completed++;
+
+ if (microtime(true) - $start > 1.5) {
+ break;
+ }
}
list ($remaining, $total, $percent) = search::stats();
diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php
index b2d55153..b9dd8c28 100644
--- a/modules/server_add/helpers/server_add_event.php
+++ b/modules/server_add/helpers/server_add_event.php
@@ -31,15 +31,11 @@ class server_add_event_Core {
$paths = unserialize(module::get_var("server_add", "authorized_paths"));
if ($item && user::active()->admin && $item->is_album() && !empty($paths)) {
- // This is a little tricky. Normally there's an "Add Photo" menu option, but we want to
- // turn that into a dropdown if there are two different ways to add things. Do that in a
- // portable way for now. If we find ourselves duplicating this pattern, we should make an
- // API method for this.
- $add_menu = $menu->get("add_menu");
- $add_menu->append(Menu::factory("dialog")
- ->id("server_add")
- ->label(t("Server add"))
- ->url(url::site("server_add/browse/$item->id")));
+ $menu->get("add_menu")
+ ->append(Menu::factory("dialog")
+ ->id("server_add")
+ ->label(t("Server add"))
+ ->url(url::site("server_add/browse/$item->id")));
}
}
}
diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css
index 82cdb331..5eb30bde 100644
--- a/themes/default/css/screen.css
+++ b/themes/default/css/screen.css
@@ -308,7 +308,7 @@ li.gError select {
.gError {
background-color: #f6cbca;
- color: #fc0;
+ color: #f00;
background-image: url('../images/ico-error.png');
}