diff options
Diffstat (limited to 'modules/gallery')
55 files changed, 1212 insertions, 413 deletions
diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php index c9d944cc..b35a9299 100644 --- a/modules/gallery/controllers/admin.php +++ b/modules/gallery/controllers/admin.php @@ -55,7 +55,7 @@ class Admin_Controller extends Controller { $method = "index"; } - if (!method_exists($controller_name, $method)) { + if (!class_exists($controller_name) || !method_exists($controller_name, $method)) { throw new Kohana_404_Exception(); } diff --git a/modules/gallery/controllers/admin_dashboard.php b/modules/gallery/controllers/admin_dashboard.php index 6bd36b07..53172109 100644 --- a/modules/gallery/controllers/admin_dashboard.php +++ b/modules/gallery/controllers/admin_dashboard.php @@ -26,6 +26,7 @@ class Admin_Dashboard_Controller extends Admin_Controller { $view->sidebar = "<div id=\"g-admin-dashboard-sidebar\">" . block_manager::get_html("dashboard_sidebar") . "</div>"; + $view->content->obsolete_modules_message = module::get_obsolete_modules_message(); print $view; } diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php index 23df33ee..32f20784 100644 --- a/modules/gallery/controllers/admin_maintenance.php +++ b/modules/gallery/controllers/admin_maintenance.php @@ -55,6 +55,7 @@ class Admin_Maintenance_Controller extends Admin_Controller { ->where("expiration", "<>", 0) ->where("expiration", "<=", time()) ->execute(); + module::deactivate_missing_modules(); } /** diff --git a/modules/gallery/controllers/admin_modules.php b/modules/gallery/controllers/admin_modules.php index d13ec1c6..177a925d 100644 --- a/modules/gallery/controllers/admin_modules.php +++ b/modules/gallery/controllers/admin_modules.php @@ -26,6 +26,7 @@ class Admin_Modules_Controller extends Admin_Controller { $view->page_title = t("Modules"); $view->content = new View("admin_modules.html"); $view->content->available = module::available(); + $view->content->obsolete_modules_message = module::get_obsolete_modules_message(); print $view; } diff --git a/modules/gallery/controllers/admin_movies.php b/modules/gallery/controllers/admin_movies.php new file mode 100644 index 00000000..38fa44a5 --- /dev/null +++ b/modules/gallery/controllers/admin_movies.php @@ -0,0 +1,72 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Admin_Movies_Controller extends Admin_Controller { + public function index() { + // Print screen from new form. + $form = $this->_get_admin_form(); + $this->_print_view($form); + } + + public function save() { + access::verify_csrf(); + $form = $this->_get_admin_form(); + if ($form->validate()) { + module::set_var("gallery", "movie_allow_uploads", $form->settings->allow_uploads->value); + if ($form->settings->rebuild_thumbs->value) { + graphics::mark_dirty(true, false, "movie"); + } + // All done - redirect with message. + message::success(t("Movies settings updated successfully")); + url::redirect("admin/movies"); + } + // Something went wrong - print view from existing form. + $this->_print_view($form); + } + + private function _print_view($form) { + list ($ffmpeg_version, $ffmpeg_date) = movie::get_ffmpeg_version(); + $ffmpeg_version = $ffmpeg_date ? "{$ffmpeg_version} ({$ffmpeg_date})" : $ffmpeg_version; + $ffmpeg_path = movie::find_ffmpeg(); + $ffmpeg_dir = substr($ffmpeg_path, 0, strrpos($ffmpeg_path, "/")); + + $view = new Admin_View("admin.html"); + $view->page_title = t("Movies settings"); + $view->content = new View("admin_movies.html"); + $view->content->form = $form; + $view->content->ffmpeg_dir = $ffmpeg_dir; + $view->content->ffmpeg_version = $ffmpeg_version; + print $view; + } + + private function _get_admin_form() { + $form = new Forge("admin/movies/save", "", "post", array("id" => "g-movies-admin-form")); + $group = $form->group("settings")->label(t("Settings")); + $group->dropdown("allow_uploads") + ->label(t("Allow movie uploads into Gallery (does not affect existing movies)")) + ->options(array("autodetect"=>t("only if FFmpeg is detected (default)"), + "always"=>t("always"), "never"=>t("never"))) + ->selected(module::get_var("gallery", "movie_allow_uploads", "autodetect")); + $group->checkbox("rebuild_thumbs") + ->label(t("Rebuild all movie thumbnails (once FFmpeg is installed, use this to update existing movie thumbnails)")) + ->checked(false); // always set as false + $form->submit("save")->value(t("Save")); + return $form; + } +} diff --git a/modules/gallery/controllers/admin_theme_options.php b/modules/gallery/controllers/admin_theme_options.php index aead8bae..38d2b0a8 100644 --- a/modules/gallery/controllers/admin_theme_options.php +++ b/modules/gallery/controllers/admin_theme_options.php @@ -34,7 +34,6 @@ class Admin_Theme_Options_Controller extends Admin_Controller { module::set_var("gallery", "page_size", $form->edit_theme->page_size->value); $thumb_size = $form->edit_theme->thumb_size->value; - $thumb_dirty = false; if (module::get_var("gallery", "thumb_size") != $thumb_size) { graphics::remove_rule("gallery", "thumb", "gallery_graphics::resize"); graphics::add_rule( @@ -45,7 +44,6 @@ class Admin_Theme_Options_Controller extends Admin_Controller { } $resize_size = $form->edit_theme->resize_size->value; - $resize_dirty = false; if (module::get_var("gallery", "resize_size") != $resize_size) { graphics::remove_rule("gallery", "resize", "gallery_graphics::resize"); graphics::add_rule( diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php index 7e5d0038..50f1aa26 100644 --- a/modules/gallery/controllers/file_proxy.php +++ b/modules/gallery/controllers/file_proxy.php @@ -66,24 +66,8 @@ class File_Proxy_Controller extends Controller { throw $e; } - // If the last element is .album.jpg, pop that off since it's not a real item - $path = preg_replace("|/.album.jpg$|", "", $path); - - $item = item::find_by_path($path); - if (!$item->loaded()) { - // We didn't turn it up. If we're looking for a .jpg then it's it's possible that we're - // requesting the thumbnail for a movie. In that case, the movie file would - // have been converted to a .jpg. So try some alternate types: - if (preg_match('/.jpg$/', $path)) { - foreach (legal_file::get_movie_extensions() as $ext) { - $movie_path = preg_replace('/.jpg$/', ".$ext", $path); - $item = item::find_by_path($movie_path); - if ($item->loaded()) { - break; - } - } - } - } + // Get the item model using the path and type (which corresponds to a var subdir) + $item = item::find_by_path($path, $type); if (!$item->loaded()) { $e = new Kohana_404_Exception(); @@ -162,7 +146,6 @@ class File_Proxy_Controller extends Controller { // going to buffer up whatever file we're proxying (and it may be very large). This may // affect embedding or systems with PHP's output_buffering enabled. while (ob_get_level()) { - Kohana_Log::add("error","".print_r(ob_get_level(),1)); if (!@ob_end_clean()) { // ob_end_clean() can return false if the buffer can't be removed for some reason // (zlib output compression buffers sometimes cause problems). diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 2ddf2a4b..4b21d9ee 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -41,7 +41,6 @@ class Quick_Controller extends Controller { gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $degrees), $item); $item->set_data_file($tmpfile); $item->save(); - unlink($tmpfile); } if (Input::instance()->get("page_type") == "collection") { diff --git a/modules/gallery/controllers/upgrader.php b/modules/gallery/controllers/upgrader.php index d3c6e2ec..6b3a9ef6 100644 --- a/modules/gallery/controllers/upgrader.php +++ b/modules/gallery/controllers/upgrader.php @@ -46,6 +46,7 @@ class Upgrader_Controller extends Controller { $view->available = module::available(); $view->failed = $failed ? explode(",", $failed) : array(); $view->done = $available_upgrades == 0; + $view->obsolete_modules_message = module::get_obsolete_modules_message(); print $view; } diff --git a/modules/gallery/controllers/uploader.php b/modules/gallery/controllers/uploader.php index 78437071..54e1476b 100644 --- a/modules/gallery/controllers/uploader.php +++ b/modules/gallery/controllers/uploader.php @@ -47,52 +47,25 @@ class Uploader_Controller extends Controller { $form = $this->_get_add_form($album); - // Uploadify adds its own field to the form, so validate that separately. - $file_validation = new Validation($_FILES); - $file_validation->add_rules( - "Filedata", "upload::valid", "upload::required", - "upload::type[" . implode(",", legal_file::get_extensions()) . "]"); - - if ($form->validate() && $file_validation->validate()) { - $temp_filename = upload::save("Filedata"); - Event::add("system.shutdown", create_function("", "unlink(\"$temp_filename\");")); + if ($form->validate()) { + // Uploadify puts the result in $_FILES["Filedata"] - process it. try { - $item = ORM::factory("item"); - $item->name = substr(basename($temp_filename), 10); // Skip unique identifier Kohana adds - $item->title = item::convert_filename_to_title($item->name); - $item->parent_id = $album->id; - $item->set_data_file($temp_filename); - - $path_info = @pathinfo($temp_filename); - if (array_key_exists("extension", $path_info) && - legal_file::get_movie_extensions($path_info["extension"])) { - $item->type = "movie"; - $item->save(); - log::success("content", t("Added a movie"), - html::anchor("movies/$item->id", t("view movie"))); - } else { - $item->type = "photo"; - $item->save(); - log::success("content", t("Added a photo"), - html::anchor("photos/$item->id", t("view photo"))); - } + list ($tmp_name, $name) = $this->_process_upload("Filedata"); + } catch (Exception $e) { + header("HTTP/1.1 400 Bad Request"); + print "ERROR: " . $e->getMessage(); + return; + } + // We have a valid upload file (of unknown type) - build an item from it. + try { + $item = $this->_add_item($id, $tmp_name, $name); module::event("add_photos_form_completed", $item, $form); + print "FILEID: $item->id"; } catch (Exception $e) { - // The Flash uploader has no good way of reporting complex errors, so just keep it simple. - Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString()); - - // Ugh. I hate to use instanceof, But this beats catching the exception separately since - // we mostly want to treat it the same way as all other exceptions - if ($e instanceof ORM_Validation_Exception) { - Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1)); - } - header("HTTP/1.1 500 Internal Server Error"); print "ERROR: " . $e->getMessage(); - return; } - print "FILEID: $item->id"; } else { header("HTTP/1.1 400 Bad Request"); print "ERROR: " . t("Invalid upload"); @@ -107,27 +80,122 @@ class Uploader_Controller extends Controller { (int)$success_count, array("error" => (int)$error_count)); } else { - print t2("Uploaded %count photo", "Uploaded %count photos", $success_count);} + print t2("Uploaded %count photo", "Uploaded %count photos", $success_count); + } } public function finish() { access::verify_csrf(); - batch::stop(); json::reply(array("result" => "success")); } - private function _get_add_form($album) { + private function _get_add_form($album) { $form = new Forge("uploader/finish", "", "post", array("id" => "g-add-photos-form")); $group = $form->group("add_photos") ->label(t("Add photos to %album_title", array("album_title" => html::purify($album->title)))); $group->uploadify("uploadify")->album($album); - $group = $form->group("actions"); - $group->uploadify_buttons(""); + $group_actions = $form->group("actions"); + $group_actions->uploadify_buttons(""); + $inputs_before_event = array_keys($form->add_photos->inputs); module::event("add_photos_form", $album, $form); + $inputs_after_event = array_keys($form->add_photos->inputs); + + // For each new input in add_photos, attach JS to make uploadify update its value. + foreach (array_diff($inputs_after_event, $inputs_before_event) as $input) { + if (!$input) { + // Likely a script input - don't do anything with it. + continue; + } + $group->uploadify->script_data($input, $group->{$input}->value); + $group->script("") + ->text("$('input[name=\"$input\"]').change(function (event) { + $('#g-uploadify').uploadifySettings('scriptData', {'$input': $(this).val()}); + });"); + } return $form; } + + /** + * Process the uploaded file. This handles the interface with Kohana's upload and validation + * code, and marks the new temp file for deletion on shutdown. It returns the temp file path + * (tmp_name) and filename (name), analogous to their respective $_FILES elements. + * If the upload is invalid, it will throw an exception. Note that no type-checking (e.g. jpg, + * mp4,...) is performed here. + * @TODO: consider moving this to a common controller which is extended by various uploaders. + * + * @param string name of $_FILES input + * @return array array($tmp_name, $name) + */ + private function _process_upload($file) { + // Validate file data. At this point, any file extension is still valid. + $file_validation = new Validation($_FILES); + $file_validation->add_rules($file, "upload::valid", "upload::required"); + if (!$file_validation->validate()) { + throw new Exception(t("Invalid upload")); + } + + // Save temp file and mark for deletion when done. + $tmp_name = upload::save($file); + system::delete_later($tmp_name); + + // Get uploaded filename. This is different than tmp_name since it hasn't been uniquified. + $name = $_FILES[$file]["name"]; + + return array($tmp_name, $name); + } + + /** + * Add photo or movie from upload. Once we have a valid file, this generates an item model + * from it. It returns the item model on success, and throws an exception and adds log entries + * on failure. + * @TODO: consider moving this to a common controller which is extended by various uploaders. + * + * @param int parent album id + * @param string temp file path (analogous to $_FILES[...]["tmp_name"]) + * @param string filename (analogous to $_FILES[...]["name"]) + * @return object new item model + */ + private function _add_item($album_id, $tmp_name, $name) { + $extension = pathinfo($name, PATHINFO_EXTENSION); + + try { + $item = ORM::factory("item"); + $item->name = $name; + $item->title = item::convert_filename_to_title($name); + $item->parent_id = $album_id; + $item->set_data_file($tmp_name); + + if (!$extension) { + throw new Exception(t("Uploaded file has no extension")); + } else if (legal_file::get_photo_extensions($extension)) { + $item->type = "photo"; + $item->save(); + log::success("content", t("Added a photo"), + html::anchor("photos/$item->id", t("view photo"))); + } else if (movie::allow_uploads() && legal_file::get_movie_extensions($extension)) { + $item->type = "movie"; + $item->save(); + log::success("content", t("Added a movie"), + html::anchor("movies/$item->id", t("view movie"))); + } else { + throw new Exception(t("Uploaded file has illegal extension")); + } + } catch (Exception $e) { + // Log errors then re-throw exception. + Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString()); + + // If we have a validation error, add an additional log entry. + if ($e instanceof ORM_Validation_Exception) { + Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1)); + } + + throw $e; + } + + return $item; + } } diff --git a/modules/gallery/css/gallery.css b/modules/gallery/css/gallery.css index 7e711156..323c2e83 100644 --- a/modules/gallery/css/gallery.css +++ b/modules/gallery/css/gallery.css @@ -149,6 +149,25 @@ text-align: center; } +/* Dialogs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/** + * Newer Themeroller-based themes do this on their own, but older + * themes need help ensuring that dialogs and overlays are on top + */ +.ui-front { + z-index: 1000 +} + +/* Autocomplete ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +.ui-autocomplete { + text-align: left; +} + +.ui-autocomplete-loading { + background: #e8e8e8 url('../images/loading-small.gif') no-repeat center center; +} + /** ******************************************************************* * 2) Admin **********************************************************************/ diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 23aed8ac..fe6b03fc 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -34,12 +34,16 @@ class album_Core { ->error_messages("length", t("Your title is too long")); $group->textarea("description")->label(t("Description")); $group->input("name")->label(t("Directory name")) - ->error_messages("no_slashes", t("The directory name can't contain the \"/\" character")) + ->error_messages("no_slashes", t("The directory name can't contain a \"/\"")) + ->error_messages("no_backslashes", t("The directory name can't contain a \"\\\"")) + ->error_messages("no_trailing_period", t("The directory name can't end in \".\"")) ->error_messages("required", t("You must provide a directory name")) ->error_messages("length", t("Your directory name is too long")) ->error_messages("conflict", t("There is already a movie, photo or album with this name")); $group->input("slug")->label(t("Internet Address")) ->error_messages( + "conflict", t("There is already a movie, photo or album with this internet address")) + ->error_messages( "reserved", t("This address is reserved and can't be used.")) ->error_messages( "not_url_safe", @@ -64,13 +68,14 @@ class album_Core { $group = $form->group("edit_item")->label(t("Edit Album")); $group->input("title")->label(t("Title"))->value($parent->title) - ->error_messages("required", t("You must provide a title")) + ->error_messages("required", t("You must provide a title")) ->error_messages("length", t("Your title is too long")); $group->textarea("description")->label(t("Description"))->value($parent->description); if ($parent->id != 1) { $group->input("name")->label(t("Directory Name"))->value($parent->name) ->error_messages("conflict", t("There is already a movie, photo or album with this name")) ->error_messages("no_slashes", t("The directory name can't contain a \"/\"")) + ->error_messages("no_backslashes", t("The directory name can't contain a \"\\\"")) ->error_messages("no_trailing_period", t("The directory name can't end in \".\"")) ->error_messages("required", t("You must provide a directory name")) ->error_messages("length", t("Your directory name is too long")); diff --git a/modules/gallery/helpers/block_manager.php b/modules/gallery/helpers/block_manager.php index bd6ca1c8..a2279468 100644 --- a/modules/gallery/helpers/block_manager.php +++ b/modules/gallery/helpers/block_manager.php @@ -35,7 +35,7 @@ class block_manager_Core { static function activate_blocks($module_name) { $block_class = "{$module_name}_block"; - if (method_exists($block_class, "get_site_list")) { + if (class_exists($block_class) && method_exists($block_class, "get_site_list")) { $blocks = call_user_func(array($block_class, "get_site_list")); foreach (array_keys($blocks) as $block_id) { block_manager::add("site_sidebar", $module_name, $block_id); @@ -61,14 +61,14 @@ class block_manager_Core { static function deactivate_blocks($module_name) { $block_class = "{$module_name}_block"; - if (method_exists($block_class, "get_site_list")) { + if (class_exists($block_class) && method_exists($block_class, "get_site_list")) { $blocks = call_user_func(array($block_class, "get_site_list")); foreach (array_keys($blocks) as $block_id) { block_manager::remove_blocks_for_module("site_sidebar", $module_name); } } - if (method_exists($block_class, "get_admin_list")) { + if (class_exists($block_class) && method_exists($block_class, "get_admin_list")) { $blocks = call_user_func(array($block_class, "get_admin_list")); foreach (array("dashboard_sidebar", "dashboard_center") as $location) { block_manager::remove_blocks_for_module($location, $module_name); @@ -89,7 +89,7 @@ class block_manager_Core { foreach (module::active() as $module) { $class_name = "{$module->name}_block"; - if (method_exists($class_name, $function)) { + if (class_exists($class_name) && method_exists($class_name, $function)) { foreach (call_user_func(array($class_name, $function)) as $id => $title) { $blocks["{$module->name}:$id"] = $title; } @@ -102,7 +102,7 @@ class block_manager_Core { $active = block_manager::get_active($location); $result = ""; foreach ($active as $id => $desc) { - if (method_exists("$desc[0]_block", "get")) { + if (class_exists("$desc[0]_block") && method_exists("$desc[0]_block", "get")) { $block = call_user_func(array("$desc[0]_block", "get"), $desc[1], $theme); if (!empty($block)) { $block->id = $id; diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index aeb1c7eb..a319b9c6 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -36,6 +36,41 @@ class gallery_event_Core { locales::set_request_locale(); } + static function gallery_shutdown() { + // Every 500th request, do a pass over var/logs and var/tmp and delete old files. + // Limit ourselves to deleting a single file so that we don't spend too much CPU + // time on it. As long as servers call this at least twice a day they'll eventually + // wind up with a clean var/logs directory because we only create 1 file a day there. + // var/tmp might be stickier because theoretically we could wind up spamming that + // dir with a lot of files. But let's start with this and refine as we go. + if (!(rand() % 500)) { + // Note that this code is roughly duplicated in gallery_task::file_cleanup + $threshold = time() - 1209600; // older than 2 weeks + foreach(array("logs", "tmp") as $dir) { + $dir = VARPATH . $dir; + if ($dh = opendir($dir)) { + while (($file = readdir($dh)) !== false) { + if ($file[0] == ".") { + continue; + } + + // Ignore directories for now, but we should really address them in the long term. + if (is_dir("$dir/$file")) { + continue; + } + + if (filemtime("$dir/$file") <= $threshold) { + unlink("$dir/$file"); + break; + } + } + } + } + } + // Delete all files marked using system::delete_later. + system::delete_marked_files(); + } + static function user_deleted($user) { $admin = identity::admin_user(); if (!empty($admin)) { // could be empty if there is not identity provider @@ -399,6 +434,10 @@ class gallery_event_Core { ->label(t("Graphics")) ->url(url::site("admin/graphics"))) ->append(Menu::factory("link") + ->id("movies_settings") + ->label(t("Movies")) + ->url(url::site("admin/movies"))) + ->append(Menu::factory("link") ->id("languages") ->label(t("Languages")) ->url(url::site("admin/languages"))) diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index 051a66cf..f1604150 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -797,6 +797,38 @@ class gallery_installer { module::set_var("gallery", "movie_allow_uploads", "autodetect"); module::set_version("gallery", $version = 56); } + + if ($version == 56) { + // Cleanup possible instances where resize_dirty of albums or movies was set to 0. This is + // unlikely to have occurred, and doesn't currently matter much since albums and movies don't + // have resize images anyway. However, it may be useful to be consistent here going forward. + db::build() + ->update("items") + ->set("resize_dirty", 1) + ->where("type", "<>", "photo") + ->execute(); + module::set_version("gallery", $version = 57); + } + + if ($version == 57) { + // In v58 we changed the Item_Model validation code to disallow files or directories with + // backslashes in them, and we need to fix any existing items that have them. This is + // pretty unlikely, as having backslashes would have probably already caused other issues for + // users, but we should check anyway. This might be slow, but if it times out it can just + // pick up where it left off. + foreach (db::build() + ->from("items") + ->select("id") + ->where(db::expr("`name` REGEXP '\\\\\\\\'"), "=", 1) // one \, 3x escaped + ->order_by("id", "asc") + ->execute() as $row) { + set_time_limit(30); + $item = ORM::factory("item", $row->id); + $item->name = str_replace("\\", "_", $item->name); + $item->save(); + } + module::set_version("gallery", $version = 58); + } } static function uninstall() { diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 856d2639..a79cb2d5 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -281,6 +281,7 @@ class gallery_task_Core { switch ($task->get("mode", "init")) { case "init": $threshold = time() - 1209600; // older than 2 weeks + // Note that this code is roughly duplicated in gallery_event::gallery_shutdown foreach(array("logs", "tmp") as $dir) { $dir = VARPATH . $dir; if ($dh = opendir($dir)) { @@ -289,6 +290,11 @@ class gallery_task_Core { continue; } + // Ignore directories for now, but we should really address them in the long term. + if (is_dir("$dir/$file")) { + continue; + } + if (filemtime("$dir/$file") <= $threshold) { $files[] = "$dir/$file"; } diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index 3c6d71e9..e5f6b0b4 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -49,6 +49,10 @@ class gallery_theme_Core { . $theme->script("l10n_client.js"); } + // Add MediaElementJS library + $buf .= $theme->script("mediaelementjs/mediaelement.js"); + $buf .= $theme->script("mediaelementjs/mediaelementplayer.js"); + $buf .= $theme->css("mediaelementjs/mediaelementplayer.css"); $buf .= $theme->css("uploadify/uploadify.css"); return $buf; } diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index e66908c4..459784c9 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -121,12 +121,6 @@ class graphics_Core { if ($item->resize_dirty && $item->is_photo()) { $ops["resize"] = $item->resize_path(); } - if (empty($ops)) { - $item->thumb_dirty = 0; - $item->resize_dirty = 0; - $item->save(); - return; - } try { foreach ($ops as $target => $output_file) { diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index 9882a9c5..bbbc81d6 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -203,10 +203,18 @@ class item_Core { /** * Find an item by its path. If there's no match, return an empty Item_Model. * NOTE: the caller is responsible for performing security checks on the resulting item. + * + * In addition to $path, $var_subdir can be specified ("albums", "resizes", or "thumbs"). This + * corresponds to the file's directory in var, which is what's used in file_proxy. By specifying + * this, we can be smarter about items whose formats get converted (e.g. movies that get jpg + * thumbs). If omitted, it defaults to "albums" which looks for identical matches between $path + * and the item name, just like pre-v3.1 behavior. + * * @param string $path + * @param string $var_subdir * @return object Item_Model */ - static function find_by_path($path) { + static function find_by_path($path, $var_subdir="albums") { $path = trim($path, "/"); // The root path name is NULL not "", hence this workaround. @@ -214,35 +222,80 @@ class item_Core { return item::root(); } + $search_full_name = true; + $album_thumb = false; + if (($var_subdir == "thumbs") && preg_match("|^(.*)/\.album\.jpg$|", $path, $matches)) { + // It's an album thumb - remove "/.album.jpg" from the path. + $path = $matches[1]; + $album_thumb = true; + } else if (($var_subdir != "albums") && preg_match("/^(.*)\.jpg$/", $path, $matches)) { + // Item itself could be non-jpg (e.g. movies) - remove .jpg from path, don't search full name. + $path = $matches[1]; + $search_full_name = false; + } + // Check to see if there's an item in the database with a matching relative_path_cache value. - // Since that field is urlencoded, we must urlencoded the components of the path. + // Since that field is urlencoded, we must urlencode the components of the path. foreach (explode("/", $path) as $part) { $encoded_array[] = rawurlencode($part); } $encoded_path = join("/", $encoded_array); - $item = ORM::factory("item") - ->where("relative_path_cache", "=", $encoded_path) - ->find(); - if ($item->loaded()) { - return $item; + if ($search_full_name) { + $item = ORM::factory("item") + ->where("relative_path_cache", "=", $encoded_path) + ->find(); + // See if the item was found and if it should have been found. + if ($item->loaded() && + (($var_subdir == "albums") || $item->is_photo() || $album_thumb)) { + return $item; + } + } else { + // Note that the below query uses LIKE with wildcard % at end, which is still sargable and + // therefore still takes advantage of the indexed relative_path_cache (i.e. still quick). + $item = ORM::factory("item") + ->where("relative_path_cache", "LIKE", Database::escape_for_like($encoded_path) . ".%") + ->find(); + // See if the item was found and should be a jpg. + if ($item->loaded() && + (($item->is_movie() && ($var_subdir == "thumbs")) || + ($item->is_photo() && (preg_match("/^(.*)\.jpg$/", $item->name))))) { + return $item; + } } // Since the relative_path_cache field is a cache, it can be unavailable. If we don't find // anything, fall back to checking the path the hard way. $paths = explode("/", $path); - foreach (ORM::factory("item") - ->where("name", "=", end($paths)) - ->where("level", "=", count($paths) + 1) - ->find_all() as $item) { - if (urldecode($item->relative_path()) == $path) { - return $item; + if ($search_full_name) { + foreach (ORM::factory("item") + ->where("name", "=", end($paths)) + ->where("level", "=", count($paths) + 1) + ->find_all() as $item) { + // See if the item was found and if it should have been found. + if ((urldecode($item->relative_path()) == $path) && + (($var_subdir == "albums") || $item->is_photo() || $album_thumb)) { + return $item; + } + } + } else { + foreach (ORM::factory("item") + ->where("name", "LIKE", Database::escape_for_like(end($paths)) . ".%") + ->where("level", "=", count($paths) + 1) + ->find_all() as $item) { + // Compare relative_path without extension (regexp same as legal_file::change_extension), + // see if it should be a jpg. + if ((preg_replace("/\.[^\.\/]*?$/", "", urldecode($item->relative_path())) == $path) && + (($item->is_movie() && ($var_subdir == "thumbs")) || + ($item->is_photo() && (preg_match("/^(.*)\.jpg$/", $item->name))))) { + return $item; + } } } + // Nothing found - return an empty item model. return new Item_Model(); } - /** * Locate an item using the URL. We assume that the url is in the form /a/b/c where each * component matches up with an item slug. If there's no match, return an empty Item_Model diff --git a/modules/gallery/helpers/legal_file.php b/modules/gallery/helpers/legal_file.php index eb9c25de..9f02fe70 100644 --- a/modules/gallery/helpers/legal_file.php +++ b/modules/gallery/helpers/legal_file.php @@ -70,7 +70,8 @@ class legal_file_Core { if (empty(self::$movie_types_by_extension)) { $types_by_extension_wrapper = new stdClass(); $types_by_extension_wrapper->types_by_extension = array( - "flv" => "video/x-flv", "mp4" => "video/mp4", "m4v" => "video/x-m4v"); + "flv" => "video/x-flv", "mp4" => "video/mp4", "m4v" => "video/x-m4v", + "webm" => "video/webm", "ogv" => "video/ogg"); module::event("movie_types_by_extension", $types_by_extension_wrapper); foreach (self::$blacklist as $key) { unset($types_by_extension_wrapper->types_by_extension[$key]); @@ -297,7 +298,7 @@ class legal_file_Core { $filename = str_replace("/", "_", $filename); $filename = str_replace("\\", "_", $filename); - // Remove extra dots from the filename. This will also remove extraneous underscores. + // Remove extra dots from the filename. Also removes extraneous and leading/trailing underscores. $filename = legal_file::smash_extensions($filename); // It's possible that the filename has no base (e.g. ".jpg") - if so, give it a generic one. @@ -307,4 +308,31 @@ class legal_file_Core { return $filename; } + + /** + * Sanitize a directory name for an album. This returns a completely legal and valid + * directory name. + * + * @param string $dirname (with no parent directory) + * @return string sanitized dirname + */ + static function sanitize_dirname($dirname) { + // It should be a dirname without a parent directory - remove all slashes (and backslashes). + $dirname = str_replace("/", "_", $dirname); + $dirname = str_replace("\\", "_", $dirname); + + // Remove extraneous and leading/trailing underscores. + $dirname = preg_replace("/[_]+/", "_", $dirname); + $dirname = trim($dirname, "_"); + + // Remove any trailing dots. + $dirname = rtrim($dirname, "."); + + // It's possible that the dirname is now empty - if so, give it a generic one. + if (empty($dirname)) { + $dirname = "album"; + } + + return $dirname; + } } diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index df258e87..1b6c8d1a 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -141,7 +141,7 @@ class module_Core { $messages = array(); $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "can_activate")) { + if (class_exists($installer_class) && method_exists($installer_class, "can_activate")) { $messages = call_user_func(array($installer_class, "can_activate")); } @@ -173,7 +173,7 @@ class module_Core { module::_add_to_path($module_name); $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "install")) { + if (class_exists($installer_class) && method_exists($installer_class, "install")) { call_user_func_array(array($installer_class, "install"), array()); } module::set_version($module_name, module::available()->$module_name->code_version); @@ -226,7 +226,7 @@ class module_Core { $version_before = module::get_version($module_name); $installer_class = "{$module_name}_installer"; $available = module::available(); - if (method_exists($installer_class, "upgrade")) { + if (class_exists($installer_class) && method_exists($installer_class, "upgrade")) { call_user_func_array(array($installer_class, "upgrade"), array($version_before)); } else { if (isset($available->$module_name->code_version)) { @@ -261,7 +261,7 @@ class module_Core { module::_add_to_path($module_name); $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "activate")) { + if (class_exists($installer_class) && method_exists($installer_class, "activate")) { call_user_func_array(array($installer_class, "activate"), array()); } @@ -288,7 +288,7 @@ class module_Core { */ static function deactivate($module_name) { $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "deactivate")) { + if (class_exists($installer_class) && method_exists($installer_class, "deactivate")) { call_user_func_array(array($installer_class, "deactivate"), array()); } @@ -303,8 +303,25 @@ class module_Core { block_manager::deactivate_blocks($module_name); - log::success( - "module", t("Deactivated module %module_name", array("module_name" => $module_name))); + if (module::info($module_name)) { + log::success( + "module", t("Deactivated module %module_name", array("module_name" => $module_name))); + } else { + log::success( + "module", t("Deactivated missing module %module_name", array("module_name" => $module_name))); + } + } + + /** + * Deactivate modules that are unavailable or missing, yet still active. + * This happens when a user deletes a module without deactivating it. + */ + static function deactivate_missing_modules() { + foreach (self::$modules as $module_name => $module) { + if (module::is_active($module_name) && !module::info($module_name)) { + module::deactivate($module_name); + } + } } /** @@ -314,7 +331,7 @@ class module_Core { */ static function uninstall($module_name) { $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "uninstall")) { + if (class_exists($installer_class) && method_exists($installer_class, "uninstall")) { call_user_func(array($installer_class, "uninstall")); } @@ -403,7 +420,7 @@ class module_Core { continue; } $class = "{$module->name}_event"; - if (method_exists($class, $function)) { + if (class_exists($class) && method_exists($class, $function)) { call_user_func_array(array($class, $function), $args); } } @@ -411,7 +428,7 @@ class module_Core { // Give the admin theme a chance to respond, if we're in admin mode. if (theme::$is_admin) { $class = theme::$admin_theme_name . "_event"; - if (method_exists($class, $function)) { + if (class_exists($class) && method_exists($class, $function)) { call_user_func_array(array($class, $function), $args); } } @@ -419,7 +436,7 @@ class module_Core { // Give the site theme a chance to respond as well. It gets a chance even in admin mode, as // long as the theme has an admin subdir. $class = theme::$site_theme_name . "_event"; - if (method_exists($class, $function)) { + if (class_exists($class) && method_exists($class, $function)) { call_user_func_array(array($class, $function), $args); } } @@ -541,4 +558,37 @@ class module_Core { static function get_version($module_name) { return module::get($module_name)->version; } + + /** + * Check if obsolete modules are active and, if so, return a warning message. + * If none are found, return null. + */ + static function get_obsolete_modules_message() { + // This is the obsolete modules list. Any active module that's on the list + // with version number at or below the one given will be considered obsolete. + // It is hard-coded here, and may be updated with future releases of Gallery. + $obsolete_modules = array("videos" => 4, "noffmpeg" => 1, "videodimensions" => 1, + "digibug" => 2); + + // Before we check the active modules, deactivate any that are missing. + module::deactivate_missing_modules(); + + $modules_found = array(); + foreach ($obsolete_modules as $module => $version) { + if (module::is_active($module) && (module::get_version($module) <= $version)) { + $modules_found[] = $module; + } + } + + if ($modules_found) { + // Need this to be on one super-long line or else the localization scanner may not work. + // (ref: http://sourceforge.net/apps/trac/gallery/ticket/1321) + return t("Recent upgrades to Gallery have made the following modules obsolete: %modules. We recommend that you <a href=\"%url_mod\">deactivate</a> the module(s). For more information, please see the <a href=\"%url_doc\">documentation page</a>.", + array("modules" => implode(", ", $modules_found), + "url_mod" => url::site("admin/modules"), + "url_doc" => "http://codex.galleryproject.org/Gallery3:User_guide:Obsolete_modules")); + } + + return null; + } } diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index eda478c7..4613df61 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -38,6 +38,7 @@ class movie_Core { ->error_messages( "conflict", t("There is already a movie, photo or album with this name")) ->error_messages("no_slashes", t("The movie name can't contain a \"/\"")) + ->error_messages("no_backslashes", t("The movie name can't contain a \"\\\"")) ->error_messages("no_trailing_period", t("The movie name can't end in \".\"")) ->error_messages("illegal_data_file_extension", t("You cannot change the movie file extension")) ->error_messages("required", t("You must provide a movie file name")) @@ -138,7 +139,8 @@ class movie_Core { * Return the path to the ffmpeg binary if one exists and is executable, or null. */ static function find_ffmpeg() { - if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) || !file_exists($ffmpeg_path)) { + if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) || + !@is_executable($ffmpeg_path)) { $ffmpeg_path = system::find_binary( "ffmpeg", module::get_var("gallery", "graphics_toolkit_path")); module::set_var("gallery", "ffmpeg_path", $ffmpeg_path); @@ -147,6 +149,34 @@ class movie_Core { } /** + * Return version number and build date of ffmpeg if found, empty string(s) if not. When using + * static builds that aren't official releases, the version numbers are strange, hence why the + * date can be useful. + */ + static function get_ffmpeg_version() { + $ffmpeg = movie::find_ffmpeg(); + if (empty($ffmpeg)) { + return array("", ""); + } + + // Find version using -h argument since -version wasn't available in early versions. + // To keep the preg_match searches quick, we'll trim the (otherwise long) result. + $cmd = escapeshellcmd($ffmpeg) . " -h 2>&1"; + $result = substr(`$cmd`, 0, 1000); + if (preg_match("/ffmpeg version (\S+)/i", $result, $matches_version)) { + // Version number found - see if we can get the build date or copyright year as well. + if (preg_match("/built on (\S+\s\S+\s\S+)/i", $result, $matches_build_date)) { + return array(trim($matches_version[1], ","), trim($matches_build_date[1], ",")); + } else if (preg_match("/copyright \S*\s?2000-(\d{4})/i", $result, $matches_copyright_date)) { + return array(trim($matches_version[1], ","), $matches_copyright_date[1]); + } else { + return array(trim($matches_version[1], ","), ""); + } + } + return array("", ""); + } + + /** * Return the width, height, mime_type, extension and duration of the given movie file. * Metadata is first generated using ffmpeg (or set to defaults if it fails), * then can be modified by other modules using movie_get_file_metadata events. @@ -163,9 +193,7 @@ class movie_Core { * -> return metadata from ffmpeg * Input is *not* standard movie type that is *not* supported by ffmpeg but is legal * -> return zero width, height, and duration; mime type and extension according to legal_file - * Input is *not* standard movie type that is *not* supported by ffmpeg and is *not* legal - * -> return zero width, height, and duration; null mime type and extension - * Input is not readable or does not exist + * Input is illegal, unidentifiable, unreadable, or does not exist * -> throw exception * Note: movie_get_file_metadata events can change any of the above cases (except the last one). */ diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index 2d32f0d3..ecf81e66 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -35,6 +35,7 @@ class photo_Core { $group->input("name")->label(t("Filename"))->value($photo->name) ->error_messages("conflict", t("There is already a movie, photo or album with this name")) ->error_messages("no_slashes", t("The photo name can't contain a \"/\"")) + ->error_messages("no_backslashes", t("The photo name can't contain a \"\\\"")) ->error_messages("no_trailing_period", t("The photo name can't end in \".\"")) ->error_messages("illegal_data_file_extension", t("You cannot change the photo file extension")) ->error_messages("required", t("You must provide a photo file name")) @@ -94,10 +95,8 @@ class photo_Core { * Input is *not* standard photo type that is supported by getimagesize (e.g. tif, bmp...) * -> return metadata from getimagesize() * Input is *not* standard photo type that is *not* supported by getimagesize but is legal - * -> return zero width and height, mime type and extension according to legal_file - * Input is *not* standard photo type that is *not* supported by getimagesize and is *not* legal - * -> return zero width and height, null mime type and extension - * Input is not readable or does not exist + * -> return metadata if found by photo_get_file_metadata events + * Input is illegal, unidentifiable, unreadable, or does not exist * -> throw exception * Note: photo_get_file_metadata events can change any of the above cases (except the last one). */ diff --git a/modules/gallery/helpers/system.php b/modules/gallery/helpers/system.php index e1398103..f0879d6a 100644 --- a/modules/gallery/helpers/system.php +++ b/modules/gallery/helpers/system.php @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class system_Core { + private static $files_marked_for_deletion = array(); + /** * Return the path to an executable version of the named binary, or null. * The paths are traversed in the following order: @@ -45,6 +47,7 @@ class system_Core { explode(":", module::get_var("gallery", "extra_binary_paths"))); foreach ($paths as $path) { + $path = rtrim($path, "/"); $candidate = "$path/$binary"; // @suppress errors below to avoid open_basedir issues if (@file_exists($candidate)) { @@ -66,8 +69,10 @@ class system_Core { * This helper is similar to the built-in tempnam. * It allows the caller to specify a prefix and an extension. * It always places the file in TMPPATH. + * Unless specified with the $delete_later argument, it will be marked + * for deletion at shutdown using system::delete_later. */ - static function temp_filename($prefix="", $extension="") { + static function temp_filename($prefix="", $extension="", $delete_later=true) { do { $basename = tempnam(TMPPATH, $prefix); if (!$basename) { @@ -79,6 +84,30 @@ class system_Core { @unlink($basename); } } while (!$success); + + if ($delete_later) { + system::delete_later($filename); + } + return $filename; } -}
\ No newline at end of file + + /** + * Mark a file for deletion at shutdown time. This is useful for temp files, where we can delay + * the deletion time until shutdown to keep page load time quick. + */ + static function delete_later($filename) { + self::$files_marked_for_deletion[] = $filename; + } + + /** + * Delete all files marked using system::delete_later. This is called at gallery shutdown. + */ + static function delete_marked_files() { + foreach (self::$files_marked_for_deletion as $filename) { + // We want to suppress all errors, as it's possible that some of these + // files may have been deleted/moved before we got here. + @unlink($filename); + } + } +} diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php index 32fd9739..5638faf4 100644 --- a/modules/gallery/helpers/task.php +++ b/modules/gallery/helpers/task.php @@ -25,7 +25,7 @@ class task_Core { $tasks = array(); foreach (module::active() as $module) { $class_name = "{$module->name}_task"; - if (method_exists($class_name, "available_tasks")) { + if (class_exists($class_name) && method_exists($class_name, "available_tasks")) { foreach (call_user_func(array($class_name, "available_tasks")) as $task) { $tasks[$task->callback] = $task; } diff --git a/modules/gallery/images/ffmpeg.png b/modules/gallery/images/ffmpeg.png Binary files differnew file mode 100644 index 00000000..6be8b62a --- /dev/null +++ b/modules/gallery/images/ffmpeg.png diff --git a/modules/gallery/images/loading-small.gif b/modules/gallery/images/loading-small.gif Binary files differnew file mode 100644 index 00000000..d0bce154 --- /dev/null +++ b/modules/gallery/images/loading-small.gif diff --git a/modules/gallery/js/albums_form_add.js b/modules/gallery/js/albums_form_add.js index a568f35d..55ad8ce6 100644 --- a/modules/gallery/js/albums_form_add.js +++ b/modules/gallery/js/albums_form_add.js @@ -1,23 +1,6 @@ -$("#g-add-album-form input[name=title]").change( - function() { - $("#g-add-album-form input[name=name]").attr( - "value", $("#g-add-album-form input[name=title]").attr("value") - .replace(/[\s\/]+/g, "-").replace(/\.+$/, "")); - $("#g-add-album-form input[name=slug]").attr( - "value", $("#g-add-album-form input[name=title]").attr("value") - .replace(/[^A-Za-z0-9-_]+/g, "-") - .replace(/^-+/, "") - .replace(/-+$/, "")); - }); -$("#g-add-album-form input[name=title]").keyup( - function() { - $("#g-add-album-form input[name=name]").attr( - "value", $("#g-add-album-form input[name=title]").attr("value") - .replace(/[\s\/]+/g, "-") - .replace(/\.+$/, "")); - $("#g-add-album-form input[name=slug]").attr( - "value", $("#g-add-album-form input[name=title]").attr("value") - .replace(/[^A-Za-z0-9-_]+/g, "-") - .replace(/^-+/, "") - .replace(/-+$/, "")); - }); +$("#g-add-album-form input[name='title']").on("input keyup", function() { + $("#g-add-album-form input[name='name']").val( + $(this).val().replace(/[\s\/\\]+/g, "-").replace(/\.+$/, "")); + $("#g-add-album-form input[name='slug']").val( + $(this).val().replace(/[^A-Za-z0-9-_]+/g, "-").replace(/^-+/, "").replace(/-+$/, "")); +}); diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js index 6d919c29..261461b9 100644 --- a/modules/gallery/js/l10n_client.js +++ b/modules/gallery/js/l10n_client.js @@ -121,11 +121,11 @@ jQuery.extend(Gallery, { translation[form] = ''; } $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']") - .attr('value', translation[form]); + .val(translation[form]); $('#plural-' + form).removeClass('hidden'); } } else { - $('#l10n-edit-translation').attr('value', translation); + $('#l10n-edit-translation').val(translation); $('#l10n-edit-translation').removeClass('hidden'); } }; @@ -167,10 +167,10 @@ jQuery.extend(Gallery, { text = source['one']; } $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']") - .attr('value', text); + .val(text); } } else { - $('#l10n-edit-translation').attr('value', source); + $('#l10n-edit-translation').val(source); } } @@ -240,7 +240,7 @@ Gallery.behaviors.l10nClient = function(context) { }); // Custom listener for l10n_client livesearch - $('#l10n-client #g-l10n-search').keyup(function(key) { + $('#l10n-client #g-l10n-search').on("input keyup", function(key) { Gallery.l10nClient.filter($('#l10n-client #g-l10n-search').val()); }); @@ -264,11 +264,11 @@ Gallery.behaviors.l10nClient = function(context) { if (is_plural) { for (var i = 0; i < num_plural_forms; i++) { var form = plural_forms[i]; - translation[form] = $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").attr('value'); + translation[form] = $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").val(); is_non_empty = is_non_empty || translation[form]; } } else { - translation = $('#l10n-edit-translation').attr('value'); + translation = $('#l10n-edit-translation').val(); is_non_empty = translation; } Gallery.l10nClient.setString(Gallery.l10nClient.selected, translation); diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php index 83163868..ba348d7a 100644 --- a/modules/gallery/libraries/Admin_View.php +++ b/modules/gallery/libraries/Admin_View.php @@ -93,24 +93,52 @@ class Admin_View_Core extends Gallery_View { case "body_attributes": case "html_attributes": $blocks = array(); + if (method_exists("gallery_theme", $function)) { + switch (count($args)) { + case 0: + $blocks[] = gallery_theme::$function($this); + break; + case 1: + $blocks[] = gallery_theme::$function($this, $args[0]); + break; + case 2: + $blocks[] = gallery_theme::$function($this, $args[0], $args[1]); + break; + default: + $blocks[] = call_user_func_array( + array("gallery_theme", $function), + array_merge(array($this), $args)); + } + } + foreach (module::active() as $module) { + if ($module->name == "gallery") { + continue; + } $helper_class = "{$module->name}_theme"; - if (method_exists($helper_class, $function)) { + if (class_exists($helper_class) && method_exists($helper_class, $function)) { $blocks[] = call_user_func_array( array($helper_class, $function), array_merge(array($this), $args)); } } + $helper_class = theme::$admin_theme_name . "_theme"; + if (class_exists($helper_class) && method_exists($helper_class, $function)) { + $blocks[] = call_user_func_array( + array($helper_class, $function), + array_merge(array($this), $args)); + } + if (Session::instance()->get("debug")) { - if ($function != "admin_head") { + if ($function != "admin_head" && $function != "body_attributes") { array_unshift( - $blocks, "<div class=\"g-annotated-theme-block g-annotated-theme-block_$function\">" . + $blocks, + "<div class=\"g-annotated-theme-block g-annotated-theme-block_$function g-clear-fix\">" . "<div class=\"title\">$function</div>"); $blocks[] = "</div>"; } } - return implode("\n", $blocks); default: diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php index 8f02b53c..3f59db6a 100644 --- a/modules/gallery/libraries/Gallery_View.php +++ b/modules/gallery/libraries/Gallery_View.php @@ -82,10 +82,9 @@ class Gallery_View_Core extends View { * @param $types a comma separated list of types to combine, eg "script,css" */ public function start_combining($types) { - if (gallery::allow_css_and_js_combining()) { - foreach (explode(",", $types) as $type) { - $this->combine_queue[$type] = array(); - } + foreach (explode(",", $types) as $type) { + // Initialize the core group so it gets included first. + $this->combine_queue[$type] = array("core" => array()); } } @@ -135,70 +134,93 @@ class Gallery_View_Core extends View { /** * Combine a series of files into a single one and cache it in the database. * @param $type the data type (script or css) - * @param $group the group of scripts or css we want + * @param $group the group of scripts or css we want (null will combine all groups) */ - public function get_combined($type, $group="core") { - $links = array(); - - if (empty($this->combine_queue[$type][$group])) { - return; + public function get_combined($type, $group=null) { + if (is_null($group)) { + $groups = array_keys($this->combine_queue[$type]); + } else { + $groups = array($group); } - // Include the url in the cache key so that if the Gallery moves, we don't use old cached - // entries. - $key = array(url::abs_file("")); + $buf = ""; + foreach ($groups as $group) { + if (empty($this->combine_queue[$type][$group])) { + continue; + } - foreach (array_keys($this->combine_queue[$type][$group]) as $path) { - $stats = stat($path); - // 7 == size, 9 == mtime, see http://php.net/stat - $key[] = "$path $stats[7] $stats[9]"; - } + // Include the url in the cache key so that if the Gallery moves, we don't use old cached + // entries. + $key = array(url::abs_file("")); + foreach (array_keys($this->combine_queue[$type][$group]) as $path) { + $stats = stat($path); + // 7 == size, 9 == mtime, see http://php.net/stat + $key[] = "$path $stats[7] $stats[9]"; + } + $key = md5(join(" ", $key)); - $key = md5(join(" ", $key)); - $cache = Cache::instance(); - $contents = $cache->get($key); + if (gallery::allow_css_and_js_combining()) { + // Combine enabled - if we're at the start of the buffer, add a comment. + if (!$buf) { + $type_text = ($type == "css") ? "CSS" : "JS"; + $buf .= "<!-- LOOKING FOR YOUR $type_text? It's all been combined into the link(s) below -->\n"; + } - if (empty($contents)) { - $combine_data = new stdClass(); - $combine_data->type = $type; - $combine_data->contents = $this->combine_queue[$type][$group]; - module::event("before_combine", $combine_data); + $cache = Cache::instance(); + $contents = $cache->get($key); - $contents = ""; - foreach (array_keys($this->combine_queue[$type][$group]) as $path) { - if ($type == "css") { - $contents .= "/* $path */\n" . $this->process_css($path) . "\n"; - } else { - $contents .= "/* $path */\n" . file_get_contents($path) . "\n"; - } - } + if (empty($contents)) { + $combine_data = new stdClass(); + $combine_data->type = $type; + $combine_data->contents = $this->combine_queue[$type][$group]; + module::event("before_combine", $combine_data); - $combine_data = new stdClass(); - $combine_data->type = $type; - $combine_data->contents = $contents; - module::event("after_combine", $combine_data); + $contents = ""; + foreach (array_keys($this->combine_queue[$type][$group]) as $path) { + if ($type == "css") { + $contents .= "/* $path */\n" . $this->process_css($path) . "\n"; + } else { + $contents .= "/* $path */\n" . file_get_contents($path) . "\n"; + } + } - $cache->set($key, $combine_data->contents, array($type), 30 * 84600); + $combine_data = new stdClass(); + $combine_data->type = $type; + $combine_data->contents = $contents; + module::event("after_combine", $combine_data); - $use_gzip = function_exists("gzencode") && - (int) ini_get("zlib.output_compression") === 0; - if ($use_gzip) { - $cache->set("{$key}_gz", gzencode($combine_data->contents, 9, FORCE_GZIP), - array($type, "gzip"), 30 * 84600); - } + $cache->set($key, $combine_data->contents, array($type), 30 * 84600); - } + $use_gzip = function_exists("gzencode") && + (int) ini_get("zlib.output_compression") === 0; + if ($use_gzip) { + $cache->set("{$key}_gz", gzencode($combine_data->contents, 9, FORCE_GZIP), + array($type, "gzip"), 30 * 84600); + } + } - unset($this->combine_queue[$type][$group]); - if (empty($this->combine_queue[$type])) { - unset($this->combine_queue[$type]); - } + if ($type == "css") { + $buf .= html::stylesheet("combined/css/$key", "screen,print,projection", true); + } else { + $buf .= html::script("combined/javascript/$key", true); + } + } else { + // Don't combine - just return the CSS and JS links (with the key as a cache buster). + foreach (array_keys($this->combine_queue[$type][$group]) as $path) { + if ($type == "css") { + $buf .= html::stylesheet("$path?m=$key", "screen,print,projection", false); + } else { + $buf .= html::script("$path?m=$key", false); + } + } + } - if ($type == "css") { - return html::stylesheet("combined/css/$key", "screen,print,projection", true); - } else { - return html::script("combined/javascript/$key", true); + unset($this->combine_queue[$type][$group]); + if (empty($this->combine_queue[$type])) { + unset($this->combine_queue[$type]); + } } + return $buf; } /** diff --git a/modules/gallery/libraries/IdentityProvider.php b/modules/gallery/libraries/IdentityProvider.php index 23368a6a..525e1695 100644 --- a/modules/gallery/libraries/IdentityProvider.php +++ b/modules/gallery/libraries/IdentityProvider.php @@ -81,7 +81,8 @@ class IdentityProvider_Core { module::set_var("gallery", "identity_provider", $new_provider); - if (method_exists("{$new_provider}_installer", "initialize")) { + if (class_exists("{$new_provider}_installer") && + method_exists("{$new_provider}_installer", "initialize")) { call_user_func("{$new_provider}_installer::initialize"); } diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 31e9d31b..179cbd41 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -153,7 +153,7 @@ class SafeString_Core { * Purify the string, removing any potentially malicious or unsafe HTML / JavaScript. */ private static function _purify_for_html($dirty_html) { - if (method_exists("purifier", "purify")) { + if (class_exists("purifier") && method_exists("purifier", "purify")) { return purifier::purify($dirty_html); } else { return self::_escape_for_html($dirty_html); diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index 986fc8a2..fbc58258 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -58,23 +58,37 @@ class Theme_View_Core extends Gallery_View { } /** - * Proportion of the current thumb_size's to default + * Proportion of the current thumb_size's to default. + * + * Themes can optionally use the $dimension parameter to choose which of the album's + * children will be used to determine the proportion. If set, the proportion will be + * calculated based on the child item with the largest width or height. + * * @param object Item_Model (optional) check the proportions for this item + * @param int (optional) minimum thumbnail width + * @param string (optional) "width" or "height" * @return int */ - public function thumb_proportion($item=null) { - // If the item is an album with children, grab the first item in that album instead. We're + public function thumb_proportion($item=null, $minimum_size=0, $dimension=null) { + if (!in_array($dimension, array("height", "width"))) { + $dimension = null; + } + + // If the item is an album with children, grab an item from that album instead. We're // interested in the size of the thumbnails in this album, not the thumbnail of the // album itself. if ($item && $item->is_album() && $item->children_count()) { - $item = $item->children(1)->current(); + $orderBy = (is_null($dimension)) ? array() + : array("thumb_".$dimension => "desc"); + + $item = $item->children(1, null, array(), $orderBy)->current(); } // By default we have a globally fixed thumbnail size In core code, we just return a fixed // proportion based on the global thumbnail size, but since modules can override that, we // return the actual proportions when we have them. if ($item && $item->has_thumb()) { - return max($item->thumb_width, $item->thumb_height) / 200; + return max($item->thumb_width, $item->thumb_height, $minimum_size) / 200; } else { // @TODO change the 200 to a theme supplied value when and if we come up with an // API to allow the theme to set defaults. @@ -89,7 +103,7 @@ class Theme_View_Core extends Gallery_View { public function siblings($limit=null, $offset=null) { return call_user_func_array( $this->siblings_callback[0], - array_merge($this->siblings_callback[1], array($offset, $limit))); + array_merge($this->siblings_callback[1], array($limit, $offset))); } public function tag() { @@ -239,7 +253,7 @@ class Theme_View_Core extends Gallery_View { continue; } $helper_class = "{$module->name}_theme"; - if (method_exists($helper_class, $function)) { + if (class_exists($helper_class) && method_exists($helper_class, $function)) { $blocks[] = call_user_func_array( array($helper_class, $function), array_merge(array($this), $args)); @@ -247,7 +261,7 @@ class Theme_View_Core extends Gallery_View { } $helper_class = theme::$site_theme_name . "_theme"; - if (method_exists($helper_class, $function)) { + if (class_exists($helper_class) && method_exists($helper_class, $function)) { $blocks[] = call_user_func_array( array($helper_class, $function), array_merge(array($this), $args)); diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 43b9a292..1d4f35da 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -365,14 +365,20 @@ class Item_Model_Core extends ORM_MPTT { $this->weight = item::get_max_weight(); } - // Process the data file info. - if (isset($this->data_file)) { - $this->_process_data_file_info(); - } else if (!$this->is_album()) { - // Unless it's an album, new items must have a data file. - $this->data_file_error = true; + if ($this->is_album()) { + // Sanitize the album name. + $this->name = legal_file::sanitize_dirname($this->name); + } else { + // Process the data file info. This also sanitizes the item name. + if (isset($this->data_file)) { + $this->_process_data_file_info(); + } else { + // New photos and movies must have a data file. + $this->data_file_error = true; + } } + // Make an url friendly slug from the name, if necessary if (empty($this->slug)) { $this->slug = item::convert_filename_to_slug(pathinfo($this->name, PATHINFO_FILENAME)); @@ -416,7 +422,7 @@ class Item_Model_Core extends ORM_MPTT { module::event("item_created", $this); } else { // Update an existing item - module::event("item_before_update", $item); + module::event("item_before_update", $this); // If any significant fields have changed, load up a copy of the original item and // keep it around. @@ -437,6 +443,11 @@ class Item_Model_Core extends ORM_MPTT { pathinfo($original->name, PATHINFO_EXTENSION), $this->type); } + // If an album's name changed, sanitize it. + if ($this->is_album() && array_key_exists("name", $this->changed)) { + $this->name = legal_file::sanitize_dirname($this->name); + } + // If an album's cover has changed (or been removed), delete any existing album cover, // reset the thumb metadata, and mark the thumb as dirty. if (array_key_exists("album_cover_item_id", $this->changed) && $this->is_album()) { @@ -737,40 +748,42 @@ class Item_Model_Core extends ORM_MPTT { } /** - * Return a view for movies. By default this is a Flowplayer v3 <script> tag, but - * movie_img events can override this and provide their own player/view. If no player/view - * is found and the movie is unsupported by Flowplayer v3, this returns a simple download link. + * Return a view for movies. By default, this uses MediaElementPlayer on an HTML5-compliant + * <video> object, but movie_img events can override this and provide their own player/view. + * If none are found and the player can't play the movie, this returns a simple download link. * @param array $extra_attrs * @return string */ public function movie_img($extra_attrs) { - $max_size = module::get_var("gallery", "resize_size", 640); + $player_width = module::get_var("gallery", "resize_size", 640); $width = $this->width; $height = $this->height; if ($width == 0 || $height == 0) { - // Not set correctly, likely because ffmpeg isn't available. Making the window 0x0 causes the - // video to be effectively unviewable. So, let's guess: set width to max_size and guess a - // height (using 4:3 aspect ratio). Once the video metadata is loaded, js in - // movieplayer.html.php will correct these values. - $width = $max_size; + // Not set correctly, likely because FFmpeg isn't available. Making the window 0x0 causes the + // player to be unviewable during loading. So, let's guess: set width to player_width and + // guess a height (using 4:3 aspect ratio). Once the video metadata is loaded, the player + // will correct these values. + $width = $player_width; $height = ceil($width * 3/4); } - $attrs = array_merge(array("id" => "g-item-id-{$this->id}"), $extra_attrs, - array("class" => "g-movie")); + $div_attrs = array_merge(array("id" => "g-item-id-{$this->id}"), $extra_attrs, + array("class" => "g-movie", "style" => "width: {$player_width}px;")); // Run movie_img events, which can either: - // - generate a view, which is used in place of the standard Flowplayer v3 player + // - generate a view, which is used in place of the standard MediaElementPlayer // (use view variable) - // - alter the arguments sent to the standard player - // (use fp_params and fp_config variables) + // - change the file sent to the player + // (use width, height, url, and filename variables) + // - alter the arguments sent to the player + // (use video_attrs and player_options variables) $movie_img = new stdClass(); - $movie_img->max_size = $max_size; $movie_img->width = $width; $movie_img->height = $height; - $movie_img->attrs = $attrs; $movie_img->url = $this->file_url(true); - $movie_img->fp_params = array(); // additional Flowplayer params values (will be json encoded) - $movie_img->fp_config = array(); // additional Flowplayer config values (will be json encoded) + $movie_img->filename = $this->name; + $movie_img->div_attrs = $div_attrs; // attrs for the outer .g-movie <div> + $movie_img->video_attrs = array(); // add'l <video> attrs + $movie_img->player_options = array(); // add'l MediaElementPlayer options (will be json encoded) $movie_img->view = array(); module::event("movie_img", $movie_img, $this); @@ -778,26 +791,26 @@ class Item_Model_Core extends ORM_MPTT { // View generated - use it $view = implode("\n", $movie_img->view); } else { - // View NOT generated - see if filetype supported by Flowplayer v3 - // Note that the extension list below is hard-coded and doesn't use the legal_file helper - // since anything else will not work in Flowplayer v3. - if (in_array(strtolower(pathinfo($this->name, PATHINFO_EXTENSION)), - array("flv", "mp4", "m4v", "mov", "f4v"))) { - // Filetype supported by Flowplayer v3 - use it (default) + // View not generated - see if the filetype is supported by MediaElementPlayer. + // Note that the extension list below doesn't use the legal_file helper but rather + // is hard-coded based on player specifications. + $extension = strtolower(pathinfo($movie_img->filename, PATHINFO_EXTENSION)); + if (in_array($extension, array("webm", "ogv", "mp4", "flv", "m4v", "mov", "f4v", "wmv"))) { + // Filetype supported by MediaElementPlayer - use it (default) $view = new View("movieplayer.html"); - $view->max_size = $movie_img->max_size; $view->width = $movie_img->width; $view->height = $movie_img->height; - $view->attrs = $movie_img->attrs; - $view->url = $movie_img->url; - $view->fp_params = $movie_img->fp_params; - $view->fp_config = $movie_img->fp_config; + $view->div_attrs = $movie_img->div_attrs; + $view->video_attrs = array_merge(array("controls" => "controls", "autoplay" => "autoplay", + "style" => "max-width: 100%"), $movie_img->video_attrs); + $view->source_attrs = array("type" => legal_file::get_movie_types_by_extension($extension), + "src" => $movie_img->url); + $view->player_options = $movie_img->player_options; } else { - // Filetype NOT supported by Flowplayer v3 - display download link - $attrs = array_merge($attrs, array("style" => "width: {$max_size}px;", - "download" => $this->name, // forces download (HTML5 only) - "class" => "g-movie g-movie-download-link")); - $view = html::anchor($this->file_url(true), t("Click here to download item."), $attrs); + // Filetype not supported by MediaElementPlayer - display download link + $div_attrs["class"] .= " g-movie-download-link"; // add class + $div_attrs["download"] = $movie_img->filename; // force download (HTML5 only) + $view = html::anchor($movie_img->url, t("Click here to download item."), $div_attrs); } } return $view; @@ -887,12 +900,17 @@ class Item_Model_Core extends ORM_MPTT { } /** - * Validate that the desired slug does not conflict. + * Validate the item slug. It can return the following error messages: + * - not_url_safe: has illegal characters + * - conflict: has conflicting slug + * - reserved (items in root only): has same slug as a controller */ public function valid_slug(Validation $v, $field) { if (preg_match("/[^A-Za-z0-9-_]/", $this->slug)) { $v->add_error("slug", "not_url_safe"); - } else if (db::build() + } + + if (db::build() ->from("items") ->where("parent_id", "=", $this->parent_id) ->where("id", "<>", $this->id) @@ -900,11 +918,20 @@ class Item_Model_Core extends ORM_MPTT { ->count_records()) { $v->add_error("slug", "conflict"); } + + if ($this->parent_id == 1 && Kohana::auto_load("{$this->slug}_Controller")) { + $v->add_error("slug", "reserved"); + return; + } } /** - * Validate the item name. It can't conflict with other names, can't contain slashes or - * trailing periods. + * Validate the item name. It can return the following error messages: + * - no_slashes: contains slashes + * - no_backslashes: contains backslashes + * - no_trailing_period: has a trailing period + * - illegal_data_file_extension (non-albums only): has double, no, or illegal extension + * - conflict: has conflicting name */ public function valid_name(Validation $v, $field) { if (strpos($this->name, "/") !== false) { @@ -912,18 +939,23 @@ class Item_Model_Core extends ORM_MPTT { return; } - if (rtrim($this->name, ".") !== $this->name) { - $v->add_error("name", "no_trailing_period"); + if (strpos($this->name, "\\") !== false) { + $v->add_error("name", "no_backslashes"); return; } - // Do not accept files with double extensions, they can cause problems on some - // versions of Apache. - if (!$this->is_album() && substr_count($this->name, ".") > 1) { - $v->add_error("name", "illegal_data_file_extension"); + if (rtrim($this->name, ".") !== $this->name) { + $v->add_error("name", "no_trailing_period"); + return; } if ($this->is_movie() || $this->is_photo()) { + if (substr_count($this->name, ".") > 1) { + // Do not accept files with double extensions, as they can + // cause problems on some versions of Apache. + $v->add_error("name", "illegal_data_file_extension"); + } + $ext = pathinfo($this->name, PATHINFO_EXTENSION); if (!$this->loaded() && !$ext) { @@ -965,11 +997,6 @@ class Item_Model_Core extends ORM_MPTT { return; } } - - if ($this->parent_id == 1 && Kohana::auto_load("{$this->slug}_Controller")) { - $v->add_error("slug", "reserved"); - return; - } } /** diff --git a/modules/gallery/module.info b/modules/gallery/module.info index 2383ec3c..49023e45 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,6 +1,6 @@ name = "Gallery 3" description = "Gallery core application" -version = 56 +version = 58 author_name = "Gallery Team" author_url = "http://codex.galleryproject.org/Gallery:Team" info_url = "http://codex.galleryproject.org/Gallery3:Modules:gallery" diff --git a/modules/gallery/tests/File_Proxy_Controller_Test.php b/modules/gallery/tests/File_Proxy_Controller_Test.php index 562100e4..06068d62 100644 --- a/modules/gallery/tests/File_Proxy_Controller_Test.php +++ b/modules/gallery/tests/File_Proxy_Controller_Test.php @@ -66,7 +66,7 @@ class File_Proxy_Controller_Test extends Gallery_Unit_Test_Case { public function movie_thumbnails_are_jpgs_test() { $movie = test::random_movie(); $name = legal_file::change_extension($movie->name, "jpg"); - $_SERVER["REQUEST_URI"] = url::file("var/thumbs/{$movie->name}"); + $_SERVER["REQUEST_URI"] = url::file("var/thumbs/$name"); $controller = new File_Proxy_Controller(); $this->assert_same($movie->thumb_path(), $controller->__call("", array())); } diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index 476faa5a..4643e6fd 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -27,7 +27,7 @@ class Html_Helper_Test extends Gallery_Unit_Test_Case { public function purify_test() { $safe_string = html::purify("hello <p >world</p>"); - $expected = method_exists("purifier", "purify") + $expected = (class_exists("purifier") && method_exists("purifier", "purify")) ? "hello <p>world</p>" : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string->unescaped()); diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php index f5b99bec..f4995c53 100644 --- a/modules/gallery/tests/Item_Helper_Test.php +++ b/modules/gallery/tests/Item_Helper_Test.php @@ -164,11 +164,9 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_same(item::root()->id, item::find_by_path("")->id); // Verify that we don't get confused by the part names, using the fallback code. - db::build() - ->update("items") - ->set(array("relative_path_cache" => null)) - ->where("id", "IN", array($level3->id, $level3b->id)) - ->execute(); + self::_remove_relative_path_caches(); + self::_remove_relative_path_caches(); + $this->assert_same( $level3->id, item::find_by_path("{$level1->name}/{$level2->name}/{$level3->name}")->id); @@ -180,11 +178,154 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case { // Verify that we don't get false positives $this->assert_false( item::find_by_path("foo/bar/baz")->loaded()); + } - // Verify that the fallback code works - $this->assert_same( - $level3b->id, - item::find_by_path("{$level1->name}/{$level2b->name}/{$level3b->name}")->id); + public function find_by_path_with_jpg_test() { + $parent = test::random_album(); + $jpg = test::random_photo($parent); + + $jpg_path = "{$parent->name}/{$jpg->name}"; + $flv_path = legal_file::change_extension($jpg_path, "flv"); + + // Check normal operation. + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "albums")->id); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "resizes")->id); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "thumbs")->id); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path)->id); + + // Check that we don't get false positives. + $this->assert_equal(null, item::find_by_path($flv_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "resizes")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($flv_path)->id); + + // Check normal operation without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "albums")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "resizes")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "thumbs")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($jpg->id, item::find_by_path($jpg_path)->id); + + // Check that we don't get false positives without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal(null, item::find_by_path($flv_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "resizes")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($flv_path)->id); + } + + public function find_by_path_with_png_test() { + $parent = test::random_album(); + $png = test::random_photo_unsaved($parent); + $png->set_data_file(MODPATH . "gallery/images/graphicsmagick.png"); + $png->save(); + + $png_path = "{$parent->name}/{$png->name}"; + $jpg_path = legal_file::change_extension($png_path, "jpg"); + + // Check normal operation. + $this->assert_equal($png->id, item::find_by_path($png_path, "albums")->id); + $this->assert_equal($png->id, item::find_by_path($png_path, "resizes")->id); + $this->assert_equal($png->id, item::find_by_path($png_path, "thumbs")->id); + $this->assert_equal($png->id, item::find_by_path($png_path)->id); + + // Check that we don't get false positives. + $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($jpg_path, "resizes")->id); + $this->assert_equal(null, item::find_by_path($jpg_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($jpg_path)->id); + + // Check normal operation without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal($png->id, item::find_by_path($png_path, "albums")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($png->id, item::find_by_path($png_path, "resizes")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($png->id, item::find_by_path($png_path, "thumbs")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($png->id, item::find_by_path($png_path)->id); + + // Check that we don't get false positives without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($jpg_path, "resizes")->id); + $this->assert_equal(null, item::find_by_path($jpg_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($jpg_path)->id); + } + + public function find_by_path_with_flv_test() { + $parent = test::random_album(); + $flv = test::random_movie($parent); + + $flv_path = "{$parent->name}/{$flv->name}"; + $jpg_path = legal_file::change_extension($flv_path, "jpg"); + + // Check normal operation. + $this->assert_equal($flv->id, item::find_by_path($flv_path, "albums")->id); + $this->assert_equal($flv->id, item::find_by_path($jpg_path, "thumbs")->id); + $this->assert_equal($flv->id, item::find_by_path($flv_path)->id); + + // Check that we don't get false positives. + $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($jpg_path)->id); + + // Check normal operation without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal($flv->id, item::find_by_path($flv_path, "albums")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($flv->id, item::find_by_path($jpg_path, "thumbs")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($flv->id, item::find_by_path($flv_path)->id); + + // Check that we don't get false positives without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($jpg_path)->id); + } + + public function find_by_path_with_album_test() { + $parent = test::random_album(); + $album = test::random_movie($parent); + + $album_path = "{$parent->name}/{$album->name}"; + $thumb_path = "{$album_path}/.album.jpg"; + + // Check normal operation. + $this->assert_equal($album->id, item::find_by_path($album_path, "albums")->id); + $this->assert_equal($album->id, item::find_by_path($thumb_path, "thumbs")->id); + $this->assert_equal($album->id, item::find_by_path($album_path)->id); + + // Check that we don't get false positives. + $this->assert_equal(null, item::find_by_path($thumb_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($album_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($thumb_path)->id); + + // Check normal operation without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal($album->id, item::find_by_path($album_path, "albums")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($album->id, item::find_by_path($thumb_path, "thumbs")->id); + self::_remove_relative_path_caches(); + $this->assert_equal($album->id, item::find_by_path($album_path)->id); + + // Check that we don't get false positives without relative path cache. + self::_remove_relative_path_caches(); + $this->assert_equal(null, item::find_by_path($thumb_path, "albums")->id); + $this->assert_equal(null, item::find_by_path($album_path, "thumbs")->id); + $this->assert_equal(null, item::find_by_path($thumb_path)->id); + } + + private function _remove_relative_path_caches() { + // This gets used *many* times in the find_by_path tests above to check the fallback code. + db::build() + ->update("items") + ->set("relative_path_cache", null) + ->execute(); } public function find_by_relative_url_test() { diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index fcb5c2ad..b6849413 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -124,11 +124,124 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_equal($fullsize_file, file_get_contents($photo->file_path())); } - public function item_rename_wont_accept_slash_test() { - $item = test::random_photo(); + public function photo_rename_wont_accept_slash_test() { + $item = test::random_photo_unsaved(); $item->name = "/no_slashes/allowed/"; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_slashes", $errors["name"]); + } + // Should be corrected on save. $item->save(); $this->assert_equal("no_slashes_allowed.jpg", $item->name); + // Should be corrected on update. + $item->name = "/no_slashes/allowed/"; + $item->save(); + $this->assert_equal("no_slashes_allowed.jpg", $item->name); + } + + public function photo_rename_wont_accept_backslash_test() { + $item = test::random_photo_unsaved(); + $item->name = "\\no_backslashes\\allowed\\"; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_backslashes", $errors["name"]); + } + // Should be corrected on save. + $item->save(); + $this->assert_equal("no_backslashes_allowed.jpg", $item->name); + // Should be corrected on update. + $item->name = "\\no_backslashes\\allowed\\"; + $item->save(); + $this->assert_equal("no_backslashes_allowed.jpg", $item->name); + } + + public function photo_rename_wont_accept_trailing_period_test() { + $item = test::random_photo_unsaved(); + $item->name = "no_trailing_period_allowed."; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_trailing_period", $errors["name"]); + } + // Should be corrected on save. + $item->save(); + $this->assert_equal("no_trailing_period_allowed.jpg", $item->name); + // Should be corrected on update. + $item->name = "no_trailing_period_allowed."; + $item->save(); + $this->assert_equal("no_trailing_period_allowed.jpg", $item->name); + } + + public function album_rename_wont_accept_slash_test() { + $item = test::random_album_unsaved(); + $item->name = "/no_album_slashes/allowed/"; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_slashes", $errors["name"]); + } + // Should be corrected on save. + $item->save(); + $this->assert_equal("no_album_slashes_allowed", $item->name); + // Should be corrected on update. + $item->name = "/no_album_slashes/allowed/"; + $item->save(); + $this->assert_equal("no_album_slashes_allowed", $item->name); + } + + public function album_rename_wont_accept_backslash_test() { + $item = test::random_album_unsaved(); + $item->name = "\\no_album_backslashes\\allowed\\"; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_backslashes", $errors["name"]); + } + // Should be corrected on save. + $item->save(); + $this->assert_equal("no_album_backslashes_allowed", $item->name); + // Should be corrected on update. + $item->name = "\\no_album_backslashes\\allowed\\"; + $item->save(); + $this->assert_equal("no_album_backslashes_allowed", $item->name); + } + + public function album_rename_wont_accept_trailing_period_test() { + $item = test::random_album_unsaved(); + $item->name = ".no_trailing_period.allowed."; + // Should fail on validate. + try { + $item->validate(); + $this->assert_true(false, "Shouldn't get here"); + } catch (ORM_Validation_Exception $e) { + $errors = $e->validation->errors(); + $this->assert_same("no_trailing_period", $errors["name"]); + } + // Should be corrected on save. + $item->save(); + $this->assert_equal(".no_trailing_period.allowed", $item->name); + // Should be corrected on update. + $item->name = ".no_trailing_period.allowed."; + $item->save(); + $this->assert_equal(".no_trailing_period.allowed", $item->name); } public function move_album_test() { @@ -362,6 +475,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $response = item::root()->as_restful_array(); $this->assert_true($response["can_edit"]); + access::deny(identity::everybody(), "edit", item::root()); identity::set_active_user(identity::guest()); $response = item::root()->as_restful_array(); $this->assert_false($response["can_edit"]); @@ -371,6 +485,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $response = item::root()->as_restful_array(); $this->assert_true($response["can_add"]); + access::deny(identity::everybody(), "add", item::root()); identity::set_active_user(identity::guest()); $response = item::root()->as_restful_array(); $this->assert_false($response["can_add"]); diff --git a/modules/gallery/tests/Legal_File_Helper_Test.php b/modules/gallery/tests/Legal_File_Helper_Test.php index 7ed5214b..aab41c41 100644 --- a/modules/gallery/tests/Legal_File_Helper_Test.php +++ b/modules/gallery/tests/Legal_File_Helper_Test.php @@ -37,7 +37,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_equal(null, legal_file::get_movie_types_by_extension("php.flv")); // invalid w/ . // No extension returns full array - $this->assert_equal(3, count(legal_file::get_movie_types_by_extension())); + $this->assert_equal(5, count(legal_file::get_movie_types_by_extension())); } public function get_types_by_extension_test() { @@ -47,7 +47,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_equal(null, legal_file::get_types_by_extension("php.flv")); // invalid w/ . // No extension returns full array - $this->assert_equal(7, count(legal_file::get_types_by_extension())); + $this->assert_equal(9, count(legal_file::get_types_by_extension())); } public function get_photo_extensions_test() { @@ -69,7 +69,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_equal(false, legal_file::get_movie_extensions("php.jpg")); // invalid w/ . // No extension returns full array - $this->assert_equal(3, count(legal_file::get_movie_extensions())); + $this->assert_equal(5, count(legal_file::get_movie_extensions())); } public function get_extensions_test() { @@ -79,12 +79,12 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_equal(false, legal_file::get_extensions("php.jpg")); // invalid w/ . // No extension returns full array - $this->assert_equal(7, count(legal_file::get_extensions())); + $this->assert_equal(9, count(legal_file::get_extensions())); } public function get_filters_test() { - // All 7 extensions both uppercase and lowercase - $this->assert_equal(14, count(legal_file::get_filters())); + // All 9 extensions both uppercase and lowercase + $this->assert_equal(18, count(legal_file::get_filters())); } public function get_photo_types_test() { @@ -94,7 +94,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { public function get_movie_types_test() { // Note that this is one *more* than movie extensions since video/flv is added. - $this->assert_equal(4, count(legal_file::get_movie_types())); + $this->assert_equal(6, count(legal_file::get_movie_types())); } public function change_extension_test() { @@ -194,4 +194,22 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { } } } + + public function sanitize_dirname_with_no_rename_test() { + $this->assert_equal("foo", legal_file::sanitize_dirname("foo")); + $this->assert_equal("foo.bar", legal_file::sanitize_dirname("foo.bar")); + $this->assert_equal(".foo.bar...baz", legal_file::sanitize_dirname(".foo.bar...baz")); + $this->assert_equal("foo bar spaces", legal_file::sanitize_dirname("foo bar spaces")); + $this->assert_equal("j'écris@un#nom_bizarre(mais quand_même_ça_passe \$ÇÀ@€", + legal_file::sanitize_dirname("j'écris@un#nom_bizarre(mais quand_même_ça_passe \$ÇÀ@€")); + } + + public function sanitize_filename_with_corrections_test() { + $this->assert_equal("foo_bar", legal_file::sanitize_dirname("/foo/bar/")); + $this->assert_equal("foo_bar", legal_file::sanitize_dirname("\\foo\\bar\\")); + $this->assert_equal(".foo..bar", legal_file::sanitize_dirname(".foo..bar.")); + $this->assert_equal("foo_bar", legal_file::sanitize_dirname("_foo__bar_")); + $this->assert_equal("album", legal_file::sanitize_dirname("_")); + $this->assert_equal("album", legal_file::sanitize_dirname(null)); + } }
\ No newline at end of file diff --git a/modules/gallery/tests/Movie_Helper_Test.php b/modules/gallery/tests/Movie_Helper_Test.php index 03fa2da9..9107827a 100644 --- a/modules/gallery/tests/Movie_Helper_Test.php +++ b/modules/gallery/tests/Movie_Helper_Test.php @@ -71,6 +71,7 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case { } catch (Exception $e) { // pass } + unlink(TMPPATH . "test_flv_with_no_extension"); } public function get_file_metadata_with_illegal_extension_test() { @@ -91,6 +92,7 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case { } catch (Exception $e) { // pass } + unlink(TMPPATH . "test_flv_with_php_extension.php"); } public function get_file_metadata_with_valid_extension_but_illegal_file_contents_test() { @@ -101,5 +103,6 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case { // therefore will never be executed. $this->assert_equal(array(0, 0, "video/x-flv", "flv", 0), movie::get_file_metadata(TMPPATH . "test_php_with_flv_extension.flv")); + unlink(TMPPATH . "test_php_with_flv_extension.flv"); } } diff --git a/modules/gallery/tests/Photo_Helper_Test.php b/modules/gallery/tests/Photo_Helper_Test.php index 79b5ccfd..7ba8324f 100644 --- a/modules/gallery/tests/Photo_Helper_Test.php +++ b/modules/gallery/tests/Photo_Helper_Test.php @@ -37,6 +37,7 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case { copy(MODPATH . "gallery/tests/test.jpg", TMPPATH . "test_jpg_with_no_extension"); $this->assert_equal(array(1024, 768, "image/jpeg", "jpg"), photo::get_file_metadata(TMPPATH . "test_jpg_with_no_extension")); + unlink(TMPPATH . "test_jpg_with_no_extension"); } public function get_file_metadata_with_illegal_extension_test() { @@ -56,6 +57,7 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case { copy(MODPATH . "gallery/tests/test.jpg", TMPPATH . "test_jpg_with_php_extension.php"); $this->assert_equal(array(1024, 768, "image/jpeg", "jpg"), photo::get_file_metadata(TMPPATH . "test_jpg_with_php_extension.php")); + unlink(TMPPATH . "test_jpg_with_php_extension.php"); } public function get_file_metadata_with_valid_extension_but_illegal_file_contents_test() { @@ -66,5 +68,6 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case { } catch (Exception $e) { // pass } + unlink(TMPPATH . "test_php_with_jpg_extension.jpg"); } } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 946410d4..dab7d7df 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -91,7 +91,7 @@ class SafeString_Test extends Gallery_Unit_Test_Case { public function purify_test() { $safe_string = SafeString::purify("hello <p >world</p>"); - $expected = method_exists("purifier", "purify") + $expected = (class_exists("purifier") && method_exists("purifier", "purify")) ? "hello <p>world</p>" : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string); @@ -100,7 +100,7 @@ class SafeString_Test extends Gallery_Unit_Test_Case { public function purify_twice_test() { $safe_string = SafeString::purify("hello <p >world</p>"); $safe_string_2 = SafeString::purify($safe_string); - $expected = method_exists("purifier", "purify") + $expected = (class_exists("purifier") && method_exists("purifier", "purify")) ? "hello <p>world</p>" : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string_2); diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt index 9473f9f6..4cd9f047 100644 --- a/modules/gallery/tests/controller_auth_data.txt +++ b/modules/gallery/tests/controller_auth_data.txt @@ -1,6 +1,5 @@ modules/comment/controllers/admin_manage_comments.php queue DIRTY_CSRF modules/comment/helpers/comment_rss.php feed DIRTY_AUTH -modules/digibug/controllers/digibug.php print_proxy DIRTY_CSRF|DIRTY_AUTH modules/g2_import/controllers/admin_g2_import.php autocomplete DIRTY_CSRF modules/g2_import/controllers/g2.php map DIRTY_CSRF modules/gallery/controllers/admin.php __call DIRTY_AUTH diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 51347f86..2152858a 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -39,12 +39,10 @@ modules/comment/views/comments.html.php 31 DIRTY_ATTR $com modules/comment/views/user_profile_comments.html.php 5 DIRTY_ATTR $comment->id modules/comment/views/user_profile_comments.html.php 10 DIRTY_JS $comment->item()->url() modules/comment/views/user_profile_comments.html.php 11 DIRTY $comment->item()->thumb_img(array(),50) -modules/digibug/views/digibug_form.html.php 4 DIRTY form::open("http://www.digibug.com/dapi/order.php") -modules/digibug/views/digibug_form.html.php 6 DIRTY form::hidden($key,$value) modules/exif/views/exif_dialog.html.php 14 DIRTY $details[$i]["caption"] modules/exif/views/exif_dialog.html.php 21 DIRTY $details[$i]["caption"] -modules/g2_import/views/admin_g2_import.html.php 7 DIRTY_JS url::site("__ARGS__") -modules/g2_import/views/admin_g2_import.html.php 52 DIRTY $form +modules/g2_import/views/admin_g2_import.html.php 5 DIRTY_JS url::site("__ARGS__") +modules/g2_import/views/admin_g2_import.html.php 47 DIRTY $form modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY_ATTR text::alternate("g-odd","g-even") modules/gallery/views/admin_block_log_entries.html.php 4 DIRTY_ATTR log::severity_class($entry->severity) modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY_JS user_profile::url($entry->user->id) @@ -58,7 +56,8 @@ modules/gallery/views/admin_block_photo_stream.html.php 5 DIRTY_JS $photo modules/gallery/views/admin_block_photo_stream.html.php 6 DIRTY photo::img_dimensions($photo->width,$photo->height,72) modules/gallery/views/admin_block_photo_stream.html.php 7 DIRTY_ATTR $photo->thumb_url() modules/gallery/views/admin_dashboard.html.php 5 DIRTY_JS $csrf -modules/gallery/views/admin_dashboard.html.php 35 DIRTY $blocks +modules/gallery/views/admin_dashboard.html.php 37 DIRTY $obsolete_modules_message +modules/gallery/views/admin_dashboard.html.php 42 DIRTY $blocks modules/gallery/views/admin_graphics.html.php 25 DIRTY newView("admin_graphics_none.html") modules/gallery/views/admin_graphics.html.php 27 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true)) modules/gallery/views/admin_graphics.html.php 34 DIRTY newView("admin_graphics_$id.html",array("tk"=>$tk->$id,"is_active"=>false)) @@ -98,19 +97,21 @@ modules/gallery/views/admin_maintenance.html.php 181 DIRTY $task- modules/gallery/views/admin_maintenance_show_log.html.php 8 DIRTY_JS url::site("admin/maintenance/save_log/$task->id?csrf=$csrf") modules/gallery/views/admin_maintenance_show_log.html.php 13 DIRTY $task->name modules/gallery/views/admin_maintenance_task.html.php 75 DIRTY $task->name -modules/gallery/views/admin_modules.html.php 51 DIRTY access::csrf_form_field() -modules/gallery/views/admin_modules.html.php 61 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/gallery/views/admin_modules.html.php 64 DIRTY form::checkbox($data,'1',module::is_active($module_name)) -modules/gallery/views/admin_modules.html.php 66 DIRTY $module_info->version -modules/gallery/views/admin_modules.html.php 74 DIRTY_JS $module_info->author_url -modules/gallery/views/admin_modules.html.php 81 DIRTY_ATTR $module_info->author_name -modules/gallery/views/admin_modules.html.php 85 DIRTY $module_info->author_name -modules/gallery/views/admin_modules.html.php 93 DIRTY_JS $module_info->info_url -modules/gallery/views/admin_modules.html.php 106 DIRTY_JS $module_info->discuss_url +modules/gallery/views/admin_modules.html.php 51 DIRTY $obsolete_modules_message +modules/gallery/views/admin_modules.html.php 57 DIRTY access::csrf_form_field() +modules/gallery/views/admin_modules.html.php 67 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/gallery/views/admin_modules.html.php 70 DIRTY form::checkbox($data,'1',module::is_active($module_name)) +modules/gallery/views/admin_modules.html.php 72 DIRTY $module_info->version +modules/gallery/views/admin_modules.html.php 80 DIRTY_JS $module_info->author_url +modules/gallery/views/admin_modules.html.php 87 DIRTY_ATTR $module_info->author_name +modules/gallery/views/admin_modules.html.php 91 DIRTY $module_info->author_name +modules/gallery/views/admin_modules.html.php 99 DIRTY_JS $module_info->info_url +modules/gallery/views/admin_modules.html.php 112 DIRTY_JS $module_info->discuss_url modules/gallery/views/admin_modules_confirm.html.php 11 DIRTY_ATTR $css_class modules/gallery/views/admin_modules_confirm.html.php 11 DIRTY $message modules/gallery/views/admin_modules_confirm.html.php 16 DIRTY access::csrf_form_field() modules/gallery/views/admin_modules_confirm.html.php 18 DIRTY form::hidden($module,1) +modules/gallery/views/admin_movies.html.php 43 DIRTY $form modules/gallery/views/admin_sidebar.html.php 50 DIRTY $available modules/gallery/views/admin_sidebar.html.php 58 DIRTY $active modules/gallery/views/admin_sidebar_blocks.html.php 4 DIRTY_ATTR $ref @@ -215,20 +216,20 @@ modules/gallery/views/menu.html.php 18 DIRTY $eleme modules/gallery/views/menu_ajax_link.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":"" modules/gallery/views/menu_ajax_link.html.php 4 DIRTY_ATTR $menu->css_class modules/gallery/views/menu_ajax_link.html.php 5 DIRTY_JS $menu->url -modules/gallery/views/menu_ajax_link.html.php 7 DIRTY $menu->ajax_handler +modules/gallery/views/menu_ajax_link.html.php 7 DIRTY_ATTR $menu->ajax_handler modules/gallery/views/menu_dialog.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":"" modules/gallery/views/menu_dialog.html.php 4 DIRTY_ATTR $menu->css_class modules/gallery/views/menu_dialog.html.php 5 DIRTY_JS $menu->url modules/gallery/views/menu_link.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":"" modules/gallery/views/menu_link.html.php 4 DIRTY_ATTR $menu->css_class modules/gallery/views/menu_link.html.php 5 DIRTY_JS $menu->url -modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($url,"",$attrs) -modules/gallery/views/movieplayer.html.php 4 DIRTY_JS $attrs["id"] -modules/gallery/views/movieplayer.html.php 5 DIRTY_JS $max_size -modules/gallery/views/movieplayer.html.php 23 DIRTY_JS url::abs_file("lib/flowplayer.swf") -modules/gallery/views/movieplayer.html.php 30 DIRTY_JS url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf") -modules/gallery/views/movieplayer.html.php 48 DIRTY_JS $width -modules/gallery/views/movieplayer.html.php 48 DIRTY_JS $height +modules/gallery/views/movieplayer.html.php 2 DIRTY html::attributes($div_attrs) +modules/gallery/views/movieplayer.html.php 3 DIRTY html::attributes($video_attrs) +modules/gallery/views/movieplayer.html.php 4 DIRTY html::attributes($source_attrs) +modules/gallery/views/movieplayer.html.php 8 DIRTY_JS $div_attrs["id"] +modules/gallery/views/movieplayer.html.php 10 DIRTY_JS $width +modules/gallery/views/movieplayer.html.php 11 DIRTY_JS $height +modules/gallery/views/movieplayer.html.php 14 DIRTY_JS url::abs_file("lib/mediaelementjs/") modules/gallery/views/permissions_browse.html.php 3 DIRTY_JS url::site("permissions/form/__ITEM__") modules/gallery/views/permissions_browse.html.php 16 DIRTY_JS url::site("permissions/change/__CMD__/__GROUP__/__PERM__/__ITEM__?csrf=$csrf") modules/gallery/views/permissions_browse.html.php 43 DIRTY_ATTR $parent->id @@ -265,14 +266,15 @@ modules/gallery/views/quick_delete_confirm.html.php 11 DIRTY $form modules/gallery/views/reauthenticate.html.php 9 DIRTY $form modules/gallery/views/upgrade_checker_block.html.php 19 DIRTY $new_version modules/gallery/views/upgrader.html.php 76 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 94 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable" -modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR in_array($id,$failed)?"failed":"" -modules/gallery/views/upgrader.html.php 103 DIRTY_ATTR $id -modules/gallery/views/upgrader.html.php 107 DIRTY $module->version -modules/gallery/views/upgrader.html.php 110 DIRTY $module->code_version -modules/gallery/views/upgrader.html.php 120 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 123 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 97 DIRTY $obsolete_modules_message +modules/gallery/views/upgrader.html.php 103 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 111 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable" +modules/gallery/views/upgrader.html.php 111 DIRTY_ATTR in_array($id,$failed)?"failed":"" +modules/gallery/views/upgrader.html.php 112 DIRTY_ATTR $id +modules/gallery/views/upgrader.html.php 116 DIRTY $module->version +modules/gallery/views/upgrader.html.php 119 DIRTY $module->code_version +modules/gallery/views/upgrader.html.php 129 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 132 DIRTY_ATTR $done?"muted":"" modules/gallery/views/user_languages_block.html.php 2 DIRTY form::dropdown("g-select-session-locale",$installed_locales,$selected) modules/gallery/views/user_profile.html.php 34 DIRTY_ATTR $user->avatar_url(40,$theme->url(,true)) modules/gallery/views/user_profile.html.php 43 DIRTY $info->view @@ -342,16 +344,15 @@ modules/rss/views/feed.mrss.php 67 DIRTY_ATTR $ite modules/rss/views/feed.mrss.php 68 DIRTY_ATTR $item->height modules/rss/views/feed.mrss.php 69 DIRTY_ATTR $item->width modules/rss/views/rss_block.html.php 6 DIRTY_JS rss::url($url) -modules/search/views/search.html.php 39 DIRTY_ATTR $item_class -modules/search/views/search.html.php 40 DIRTY_JS $item->url() -modules/search/views/search.html.php 41 DIRTY $item->thumb_img(array("class"=>"g-thumbnail")) modules/search/views/search.html.php 43 DIRTY_ATTR $item_class -modules/search/views/search.html.php 53 DIRTY $theme->paginator() -modules/search/views/search_link.html.php 14 DIRTY_ATTR $item->id -modules/search/views/search_link.html.php 16 DIRTY_ATTR $item->parent_id -modules/server_add/views/admin_server_add.html.php 8 DIRTY_JS url::site("__ARGS__") -modules/server_add/views/admin_server_add.html.php 19 DIRTY $form -modules/server_add/views/admin_server_add.html.php 30 DIRTY_ATTR $id +modules/search/views/search.html.php 44 DIRTY_JS $item->url() +modules/search/views/search.html.php 45 DIRTY $item->thumb_img(array("class"=>"g-thumbnail")) +modules/search/views/search.html.php 47 DIRTY_ATTR $item_class +modules/search/views/search.html.php 57 DIRTY $theme->paginator() +modules/search/views/search_link.html.php 15 DIRTY_ATTR $album_id +modules/server_add/views/admin_server_add.html.php 6 DIRTY_JS url::site("__ARGS__") +modules/server_add/views/admin_server_add.html.php 14 DIRTY $form +modules/server_add/views/admin_server_add.html.php 25 DIRTY_ATTR $id modules/server_add/views/server_add_tree.html.php 20 DIRTY_ATTR is_dir($file)?"ui-icon-folder-collapsed":"ui-icon-document" modules/server_add/views/server_add_tree.html.php 21 DIRTY_ATTR is_dir($file)?"g-directory":"g-file" modules/server_add/views/server_add_tree_dialog.html.php 3 DIRTY_JS url::site("server_add/children?path=__PATH__") @@ -359,8 +360,8 @@ modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY_JS url::s modules/server_add/views/server_add_tree_dialog.html.php 21 DIRTY $tree modules/tag/views/admin_tags.html.php 45 DIRTY_ATTR $tag->id modules/tag/views/admin_tags.html.php 46 DIRTY $tag->count -modules/tag/views/tag_block.html.php 28 DIRTY $cloud -modules/tag/views/tag_block.html.php 30 DIRTY $form +modules/tag/views/tag_block.html.php 26 DIRTY $cloud +modules/tag/views/tag_block.html.php 28 DIRTY $form modules/tag/views/tag_cloud.html.php 4 DIRTY_ATTR (int)(($tag->count/$max_count)*7) modules/tag/views/tag_cloud.html.php 5 DIRTY $tag->count modules/tag/views/tag_cloud.html.php 6 DIRTY_JS $tag->url() @@ -387,19 +388,19 @@ modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $url themes/admin_wind/views/admin.html.php 4 DIRTY $theme->html_attributes() themes/admin_wind/views/admin.html.php 34 DIRTY $theme->admin_head() themes/admin_wind/views/admin.html.php 46 DIRTY_JS $theme->url() -themes/admin_wind/views/admin.html.php 51 DIRTY $theme->get_combined("css") -themes/admin_wind/views/admin.html.php 54 DIRTY $theme->get_combined("script") -themes/admin_wind/views/admin.html.php 58 DIRTY $theme->admin_page_top() -themes/admin_wind/views/admin.html.php 66 DIRTY $theme->admin_header_top() -themes/admin_wind/views/admin.html.php 67 DIRTY_JS item::root()->url() -themes/admin_wind/views/admin.html.php 70 DIRTY $theme->user_menu() -themes/admin_wind/views/admin.html.php 73 DIRTY $theme->admin_menu() -themes/admin_wind/views/admin.html.php 76 DIRTY $theme->admin_header_bottom() -themes/admin_wind/views/admin.html.php 83 DIRTY $content -themes/admin_wind/views/admin.html.php 89 DIRTY $sidebar -themes/admin_wind/views/admin.html.php 94 DIRTY $theme->admin_footer() -themes/admin_wind/views/admin.html.php 97 DIRTY $theme->admin_credits() -themes/admin_wind/views/admin.html.php 102 DIRTY $theme->admin_page_bottom() +themes/admin_wind/views/admin.html.php 50 DIRTY $theme->get_combined("css") +themes/admin_wind/views/admin.html.php 51 DIRTY $theme->get_combined("script") +themes/admin_wind/views/admin.html.php 55 DIRTY $theme->admin_page_top() +themes/admin_wind/views/admin.html.php 63 DIRTY $theme->admin_header_top() +themes/admin_wind/views/admin.html.php 64 DIRTY_JS item::root()->url() +themes/admin_wind/views/admin.html.php 67 DIRTY $theme->user_menu() +themes/admin_wind/views/admin.html.php 70 DIRTY $theme->admin_menu() +themes/admin_wind/views/admin.html.php 73 DIRTY $theme->admin_header_bottom() +themes/admin_wind/views/admin.html.php 80 DIRTY $content +themes/admin_wind/views/admin.html.php 86 DIRTY $sidebar +themes/admin_wind/views/admin.html.php 91 DIRTY $theme->admin_footer() +themes/admin_wind/views/admin.html.php 94 DIRTY $theme->admin_credits() +themes/admin_wind/views/admin.html.php 99 DIRTY $theme->admin_page_bottom() themes/admin_wind/views/block.html.php 3 DIRTY_ATTR $anchor themes/admin_wind/views/block.html.php 5 DIRTY $id themes/admin_wind/views/block.html.php 5 DIRTY_ATTR $css_id @@ -434,18 +435,18 @@ themes/wind/views/page.html.php 10 DIRTY $page_ themes/wind/views/page.html.php 32 DIRTY $new_width themes/wind/views/page.html.php 33 DIRTY $new_height themes/wind/views/page.html.php 34 DIRTY $thumb_proportion -themes/wind/views/page.html.php 74 DIRTY_JS $theme->url() -themes/wind/views/page.html.php 79 DIRTY $theme->get_combined("css") -themes/wind/views/page.html.php 82 DIRTY $theme->get_combined("script") -themes/wind/views/page.html.php 92 DIRTY $header_text -themes/wind/views/page.html.php 94 DIRTY_JS item::root()->url() -themes/wind/views/page.html.php 98 DIRTY $theme->user_menu() -themes/wind/views/page.html.php 113 DIRTY_ATTR $breadcrumb->last?"g-active":"" -themes/wind/views/page.html.php 114 DIRTY_ATTR $breadcrumb->first?"g-first":"" -themes/wind/views/page.html.php 115 DIRTY_JS $breadcrumb->url -themes/wind/views/page.html.php 128 DIRTY $content -themes/wind/views/page.html.php 134 DIRTY newView("sidebar.html") -themes/wind/views/page.html.php 141 DIRTY $footer_text +themes/wind/views/page.html.php 68 DIRTY_JS $theme->url() +themes/wind/views/page.html.php 72 DIRTY $theme->get_combined("css") +themes/wind/views/page.html.php 73 DIRTY $theme->get_combined("script") +themes/wind/views/page.html.php 83 DIRTY $header_text +themes/wind/views/page.html.php 85 DIRTY_JS item::root()->url() +themes/wind/views/page.html.php 89 DIRTY $theme->user_menu() +themes/wind/views/page.html.php 104 DIRTY_ATTR $breadcrumb->last?"g-active":"" +themes/wind/views/page.html.php 105 DIRTY_ATTR $breadcrumb->first?"g-first":"" +themes/wind/views/page.html.php 106 DIRTY_JS $breadcrumb->url +themes/wind/views/page.html.php 119 DIRTY $content +themes/wind/views/page.html.php 125 DIRTY newView("sidebar.html") +themes/wind/views/page.html.php 132 DIRTY $footer_text themes/wind/views/paginator.html.php 33 DIRTY_JS $first_page_url themes/wind/views/paginator.html.php 42 DIRTY_JS $previous_page_url themes/wind/views/paginator.html.php 70 DIRTY_JS $next_page_url diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php index 6745f0df..f4f0c81d 100644 --- a/modules/gallery/views/admin_advanced_settings.html.php +++ b/modules/gallery/views/admin_advanced_settings.html.php @@ -39,8 +39,8 @@ <script> $(document).ready(function() { - $("#g-admin-advanced-settings-filter").keyup(function() { - var filter = $(this).attr("value"); + $("#g-admin-advanced-settings-filter").on("input keyup", function() { + var filter = $(this).val(); if (filter) { $("tr.setting-row").fadeOut("fast"); $("tr.setting-row").each(function() { diff --git a/modules/gallery/views/admin_dashboard.html.php b/modules/gallery/views/admin_dashboard.html.php index f391547e..cf90ef28 100644 --- a/modules/gallery/views/admin_dashboard.html.php +++ b/modules/gallery/views/admin_dashboard.html.php @@ -31,6 +31,13 @@ }); }); </script> +<div> + <? if ($obsolete_modules_message): ?> + <p class="g-warning"> + <?= $obsolete_modules_message ?> + </p> + <? endif ?> +</div> <div id="g-admin-dashboard"> <?= $blocks ?> </div> diff --git a/modules/gallery/views/admin_modules.html.php b/modules/gallery/views/admin_modules.html.php index 5a7f7b6c..96576ae4 100644 --- a/modules/gallery/views/admin_modules.html.php +++ b/modules/gallery/views/admin_modules.html.php @@ -46,6 +46,12 @@ <?= t("Power up your Gallery by <a href=\"%url\">adding more modules</a>! Each module provides new cool features.", array("url" => "http://codex.galleryproject.org/Category:Gallery_3:Modules")) ?> </p> + <? if ($obsolete_modules_message): ?> + <p class="g-warning"> + <?= $obsolete_modules_message ?> + </p> + <? endif ?> + <div class="g-block-content"> <form id="g-module-update-form" method="post" action="<?= url::site("admin/modules/confirm") ?>"> <?= access::csrf_form_field() ?> diff --git a/modules/gallery/views/admin_movies.html.php b/modules/gallery/views/admin_movies.html.php new file mode 100644 index 00000000..abf8fb29 --- /dev/null +++ b/modules/gallery/views/admin_movies.html.php @@ -0,0 +1,44 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<div id="g-movies-admin" class="g-block ui-helper-clearfix"> + <h1> <?= t("Movies settings") ?> </h1> + <p> + <?= t("Gallery comes with everything it needs to upload and play movies.") ?> + <?= t("However, it needs the FFmpeg toolkit to extract thumbnails and size information from them.") ?> + </p> + <p> + <?= t("Although popular, FFmpeg is not installed on all Linux systems.") ?> + <?= t("To use FFmpeg without fully installing it, download a pre-compiled, <b>static build</b> of FFmpeg from one of the links <a href=\"%url\">here</a>.", array("url" => "http://ffmpeg.org/download.html")) ?> + <?= t("Then, put the \"ffmpeg\" file in Gallery's \"bin\" directory (e.g. \"/gallery3/bin\"), where Gallery will auto-detect it.") ?> + </p> + <p> + <?= t("Movies will work without FFmpeg, but their thumbnails will be placeholders.") ?> + </p> + <p> + <?= t("Can't get FFmpeg configured on your system? <a href=\"%url\">We can help!</a>", + array("url" => "http://codex.galleryproject.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?> + </p> + + <div class="g-available"> + <h2> <?= t("Current configuration") ?> </h2> + <div id="g-ffmpeg" class="g-block"> + <img class="logo" width="284" height="70" src="<?= url::file("modules/gallery/images/ffmpeg.png") ?>" alt="<? t("Visit the FFmpeg project site") ?>" /> + <p> + <?= t("FFmpeg is a cross-platform standalone audio/video program.") ?><br/> + <?= t("Please refer to the <a href=\"%url\">FFmpeg website</a> for more information.", array("url" => "http://ffmpeg.org")) ?> + </p> + <div class="g-module-status g-info"> + <? if ($ffmpeg_dir): ?> + <? if ($ffmpeg_version): ?> + <p><?= t("FFmpeg version %version was found in %dir", array("version" => $ffmpeg_version, "dir" => $ffmpeg_dir)) ?></p> + <? else: ?> + <p><?= t("FFmpeg (of unknown version) was found in %dir", array("dir" => $ffmpeg_dir)) ?></p> + <? endif ?> + <? else: ?> + <p><?= t("We could not locate FFmpeg on your system.") ?></p> + <? endif ?> + </div> + </div> + </div> + + <?= $form ?> +</div> diff --git a/modules/gallery/views/form_uploadify.html.php b/modules/gallery/views/form_uploadify.html.php index 4426514a..c13e3418 100644 --- a/modules/gallery/views/form_uploadify.html.php +++ b/modules/gallery/views/form_uploadify.html.php @@ -131,7 +131,7 @@ <? if (identity::active_user()->admin && !$movies_allowed): ?> <p class="g-warning"> - <?= t("Can't find <i>ffmpeg</i> on your system. Movie uploading disabled. <a href=\"%help_url\">Help!</a>", array("help_url" => "http://codex.galleryproject.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?> + <?= t("Movie uploading is disabled on your system. <a href=\"%help_url\">Help!</a>", array("help_url" => url::site("admin/movies"))) ?> </p> <? endif ?> </div> diff --git a/modules/gallery/views/in_place_edit.html.php b/modules/gallery/views/in_place_edit.html.php index 2d6cbe90..c2515a03 100644 --- a/modules/gallery/views/in_place_edit.html.php +++ b/modules/gallery/views/in_place_edit.html.php @@ -8,7 +8,7 @@ <li> <?= form::submit(array("class" => "submit ui-state-default"), t("Save")) ?> </li> - <li><a href="#" class="g-cancel"><?= t("Cancel") ?></a></li> + <li><button class="g-cancel ui-state-default ui-corner-all"><?= t("Cancel") ?></button></li> <? if (!empty($errors["input"])): ?> <li> <p id="g-in-place-edit-message" class="g-error"><?= $errors["input"] ?></p> diff --git a/modules/gallery/views/menu_ajax_link.html.php b/modules/gallery/views/menu_ajax_link.html.php index 06cd6f92..66df84c9 100644 --- a/modules/gallery/views/menu_ajax_link.html.php +++ b/modules/gallery/views/menu_ajax_link.html.php @@ -4,7 +4,7 @@ class="g-ajax-link <?= $menu->css_class ?>" href="<?= $menu->url ?>" title="<?= $menu->label->for_html_attr() ?>" - ajax_handler="<?= $menu->ajax_handler ?>"> + data-ajax-handler="<?= $menu->ajax_handler ?>"> <?= $menu->label->for_html() ?> </a> </li> diff --git a/modules/gallery/views/movieplayer.html.php b/modules/gallery/views/movieplayer.html.php index edb5184c..f78cc91a 100644 --- a/modules/gallery/views/movieplayer.html.php +++ b/modules/gallery/views/movieplayer.html.php @@ -1,49 +1,17 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> -<?= html::anchor($url, "", $attrs) ?> +<div <?= html::attributes($div_attrs) ?>> + <video <?= html::attributes($video_attrs) ?>> + <source <?= html::attributes($source_attrs) ?>> + </video> +</div> <script type="text/javascript"> - var id = "<?= $attrs["id"] ?>"; - var max_size = <?= $max_size ?>; - // set the size of the movie html anchor, taking into account max_size and height of control bar - function set_movie_size(width, height) { - if((width > max_size) || (height > max_size)) { - if (width > height) { - height = Math.ceil(height * max_size / width); - width = max_size; - } else { - width = Math.ceil(width * max_size / height); - height = max_size; - } - } - height += flowplayer(id).getConfig().plugins.controls.height; - $("#" + id).css({width: width, height: height}); - }; - // setup flowplayer - flowplayer(id, + $("#<?= $div_attrs["id"] ?> video").mediaelementplayer( $.extend(true, { - "src": "<?= url::abs_file("lib/flowplayer.swf") ?>", - "wmode": "transparent", - "provider": "pseudostreaming" - }, <?= json_encode($fp_params) ?>), - $.extend(true, { - "plugins": { - "pseudostreaming": { - "url": "<?= url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf") ?>" - }, - "controls": { - "autoHide": "always", - "hideDelay": 2000, - "height": 24 - } - }, - "clip": { - "scaling": "fit", - "onMetaData": function(clip) { - // set movie size a second time using actual size from metadata - set_movie_size(parseInt(clip.metaData.width), parseInt(clip.metaData.height)); - } - } - }, <?= json_encode($fp_config) ?>) - ).ipad(); - // set movie size using width and height passed from movie_img function - $("document").ready(set_movie_size(<?= $width ?>, <?= $height ?>)); + defaultVideoWidth: <?= $width ?>, + defaultVideoHeight: <?= $height ?>, + startVolume: 1.0, + features: ["playpause", "progress", "current", "duration", "volume", "fullscreen"], + pluginPath: "<?= url::abs_file("lib/mediaelementjs/") ?>" + }, <?= json_encode($player_options) ?>) + ); </script> diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php index edfaf720..2e485c08 100644 --- a/modules/gallery/views/upgrader.html.php +++ b/modules/gallery/views/upgrader.html.php @@ -17,7 +17,7 @@ <a id="dialog_close_link" style="display: none" onclick="$('#dialog').fadeOut(); return false;" href="#" class="close">[x]</a> <div id="busy" style="display: none"> <h1> - <img width="16" height="16" src="<?= url::file("themes/wind/images/loading-small.gif") ?>"/> + <img width="16" height="16" src="<?= url::file("modules/gallery/images/loading-small.gif") ?>"/> <?= t("Upgrade in progress!") ?> </h1> <p> @@ -90,6 +90,15 @@ </div> <? endif ?> + <? if ($obsolete_modules_message): ?> + <div id="obsolete_modules_message"> + <p> + <span class="failed"><?= t("Warning!") ?></span> + <?= $obsolete_modules_message ?> + </p> + </div> + <? endif ?> + <table> <tr class="<?= $done ? "muted" : "" ?>"> <th class="name"> <?= t("Module name") ?> </th> |